From dd35d23be5196f84438531108f3885a4f24a370e Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Mon, 9 Sep 2024 21:08:00 +0000 Subject: [PATCH 01/71] Update proto for v1 backend --- Makefile | 3 +- pkg/tempopb/tempo.pb.go | 357 ++++----- pkg/tempopb/tempo.proto | 2 + tempodb/backend/v1/v1.pb.go | 1508 +++++++++++++++++++++++++++++++++++ tempodb/backend/v1/v1.proto | 41 + 5 files changed, 1732 insertions(+), 179 deletions(-) create mode 100644 tempodb/backend/v1/v1.pb.go create mode 100644 tempodb/backend/v1/v1.proto diff --git a/Makefile b/Makefile index 0d409e43ed3..15d88adb4bf 100644 --- a/Makefile +++ b/Makefile @@ -222,7 +222,7 @@ PROTOC = docker run --rm -u ${shell id -u} -v${PWD}:${PWD} -w${PWD} ${DOCKER_PRO PROTO_INTERMEDIATE_DIR = pkg/.patched-proto PROTO_INCLUDES = -I$(PROTO_INTERMEDIATE_DIR) PROTO_GEN = $(PROTOC) $(PROTO_INCLUDES) --gogofaster_out=plugins=grpc,paths=source_relative:$(2) $(1) -PROTO_GEN_WITH_VENDOR = $(PROTOC) $(PROTO_INCLUDES) -Ivendor -Ivendor/github.com/gogo/protobuf --gogofaster_out=plugins=grpc,paths=source_relative:$(2) $(1) +PROTO_GEN_WITH_VENDOR = $(PROTOC) $(PROTO_INCLUDES) -Ivendor -Ivendor/github.com/gogo/protobuf -Ipkg/tempopb --gogofaster_out=plugins=grpc,paths=source_relative:$(2) $(1) .PHONY: gen-proto gen-proto: ## Generate proto files @@ -264,6 +264,7 @@ gen-proto: ## Generate proto files $(call PROTO_GEN,$(PROTO_INTERMEDIATE_DIR)/resource/v1/resource.proto,./pkg/tempopb/) $(call PROTO_GEN,$(PROTO_INTERMEDIATE_DIR)/trace/v1/trace.proto,./pkg/tempopb/) $(call PROTO_GEN,pkg/tempopb/tempo.proto,./) + $(call PROTO_GEN,tempodb/backend/v1/v1.proto,./) $(call PROTO_GEN_WITH_VENDOR,modules/frontend/v1/frontendv1pb/frontend.proto,./) rm -rf $(PROTO_INTERMEDIATE_DIR) diff --git a/pkg/tempopb/tempo.pb.go b/pkg/tempopb/tempo.pb.go index 065003baac0..5777c96ae80 100644 --- a/pkg/tempopb/tempo.pb.go +++ b/pkg/tempopb/tempo.pb.go @@ -3425,184 +3425,185 @@ func init() { func init() { proto.RegisterFile("pkg/tempopb/tempo.proto", fileDescriptor_f22805646f4f62b6) } var fileDescriptor_f22805646f4f62b6 = []byte{ - // 2818 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x1a, 0x4d, 0x6f, 0x1b, 0xc7, - 0x55, 0x2b, 0x7e, 0x3f, 0x92, 0x12, 0x35, 0x56, 0x14, 0x9a, 0x76, 0x64, 0x65, 0x63, 0xa4, 0x6a, - 0x3e, 0x28, 0x99, 0xb1, 0x91, 0x38, 0x69, 0x53, 0x48, 0x16, 0xeb, 0x28, 0xd1, 0x57, 0x86, 0x8c, - 0x12, 0x14, 0x01, 0x84, 0x15, 0x39, 0xa6, 0x17, 0x22, 0x77, 0x99, 0xdd, 0xa5, 0x62, 0xf5, 0x50, - 0xa0, 0x05, 0x7a, 0x28, 0xd0, 0x43, 0x0f, 0xed, 0xa1, 0xc7, 0x9e, 0x8a, 0x9e, 0x7a, 0x68, 0xff, - 0x41, 0x81, 0x22, 0x40, 0xd1, 0x20, 0x40, 0x2f, 0x41, 0x0f, 0x41, 0x91, 0x1c, 0xda, 0x9f, 0x51, - 0xcc, 0x9b, 0x99, 0xdd, 0x59, 0x72, 0x29, 0xc5, 0x8d, 0x82, 0xe6, 0x90, 0x93, 0xe6, 0xbd, 0x7d, - 0xf3, 0xe6, 0xcd, 0xfb, 0x7e, 0x43, 0xc1, 0x93, 0xc3, 0x93, 0xde, 0x5a, 0xc0, 0x06, 0x43, 0x77, - 0x78, 0x2c, 0xfe, 0xd6, 0x87, 0x9e, 0x1b, 0xb8, 0x24, 0x27, 0x91, 0xb5, 0xa5, 0x8e, 0x3b, 0x18, - 0xb8, 0xce, 0xda, 0xe9, 0xad, 0x35, 0xb1, 0x12, 0x04, 0xb5, 0x17, 0x7b, 0x76, 0xf0, 0x70, 0x74, - 0x5c, 0xef, 0xb8, 0x83, 0xb5, 0x9e, 0xdb, 0x73, 0xd7, 0x10, 0x7d, 0x3c, 0x7a, 0x80, 0x10, 0x02, - 0xb8, 0x92, 0xe4, 0x8b, 0x81, 0x67, 0x75, 0x18, 0xe7, 0x82, 0x0b, 0x81, 0x35, 0xff, 0x6c, 0x40, - 0xa5, 0xcd, 0xe1, 0xcd, 0xb3, 0xed, 0x2d, 0xca, 0x3e, 0x18, 0x31, 0x3f, 0x20, 0x55, 0xc8, 0x21, - 0xcd, 0xf6, 0x56, 0xd5, 0x58, 0x31, 0x56, 0x4b, 0x54, 0x81, 0x64, 0x19, 0xe0, 0xb8, 0xef, 0x76, - 0x4e, 0x5a, 0x81, 0xe5, 0x05, 0xd5, 0xd9, 0x15, 0x63, 0xb5, 0x40, 0x35, 0x0c, 0xa9, 0x41, 0x1e, - 0xa1, 0xa6, 0xd3, 0xad, 0xa6, 0xf0, 0x6b, 0x08, 0x93, 0xeb, 0x50, 0xf8, 0x60, 0xc4, 0xbc, 0xb3, - 0x5d, 0xb7, 0xcb, 0xaa, 0x19, 0xfc, 0x18, 0x21, 0xc8, 0x0b, 0xb0, 0x60, 0xf5, 0xfb, 0xee, 0x87, - 0x07, 0x96, 0x17, 0xd8, 0x56, 0x1f, 0x65, 0xaa, 0x66, 0x57, 0x8c, 0xd5, 0x3c, 0x9d, 0xfc, 0x60, - 0xfe, 0xc7, 0x80, 0x05, 0x4d, 0x6c, 0x7f, 0xe8, 0x3a, 0x3e, 0x23, 0x37, 0x21, 0x83, 0x82, 0xa2, - 0xd4, 0xc5, 0xc6, 0x5c, 0x5d, 0xaa, 0xb0, 0x8e, 0xa4, 0x54, 0x7c, 0x24, 0x2f, 0x41, 0x6e, 0xc0, - 0x02, 0xcf, 0xee, 0xf8, 0x78, 0x81, 0x62, 0xe3, 0x6a, 0x9c, 0x8e, 0xb3, 0xdc, 0x15, 0x04, 0x54, - 0x51, 0x92, 0xbb, 0x90, 0xf5, 0x03, 0x2b, 0x18, 0xf9, 0x78, 0xad, 0xb9, 0xc6, 0xd3, 0x93, 0x7b, - 0x94, 0x18, 0xf5, 0x16, 0x12, 0x52, 0xb9, 0x81, 0x6b, 0x73, 0xc0, 0x7c, 0xdf, 0xea, 0xb1, 0x6a, - 0x1a, 0x6f, 0xad, 0x40, 0xf3, 0x19, 0xc8, 0x0a, 0x5a, 0x52, 0x82, 0xfc, 0xbd, 0xfd, 0xdd, 0x83, - 0x9d, 0x66, 0xbb, 0x59, 0x99, 0x21, 0x45, 0xc8, 0x1d, 0x6c, 0xd0, 0xf6, 0xf6, 0xc6, 0x4e, 0xc5, - 0x30, 0x89, 0x66, 0x20, 0x29, 0x96, 0xf9, 0xf1, 0x2c, 0x94, 0x5b, 0xcc, 0xf2, 0x3a, 0x0f, 0x95, - 0xc9, 0x5e, 0x85, 0x74, 0xdb, 0xea, 0xf9, 0x55, 0x63, 0x25, 0xb5, 0x5a, 0x6c, 0xac, 0x84, 0xd2, - 0xc5, 0xa8, 0xea, 0x9c, 0xa4, 0xe9, 0x04, 0xde, 0xd9, 0x66, 0xfa, 0xa3, 0xcf, 0x6e, 0xcc, 0x50, - 0xdc, 0x43, 0x6e, 0x42, 0x79, 0xd7, 0x76, 0xb6, 0x46, 0x9e, 0x15, 0xd8, 0xae, 0xb3, 0x2b, 0xd4, - 0x52, 0xa6, 0x71, 0x24, 0x52, 0x59, 0x8f, 0x34, 0xaa, 0x94, 0xa4, 0xd2, 0x91, 0x64, 0x11, 0x32, - 0x3b, 0xf6, 0xc0, 0x0e, 0xf0, 0xaa, 0x65, 0x2a, 0x00, 0x8e, 0xf5, 0xd1, 0x63, 0x32, 0x02, 0x8b, - 0x00, 0xa9, 0x40, 0x8a, 0x39, 0x5d, 0x34, 0x72, 0x99, 0xf2, 0x25, 0xa7, 0x7b, 0x9b, 0x7b, 0x44, - 0x35, 0x8f, 0x8a, 0x12, 0x00, 0x59, 0x85, 0xf9, 0xd6, 0xd0, 0x72, 0xfc, 0x03, 0xe6, 0xf1, 0xbf, - 0x2d, 0x16, 0x54, 0x0b, 0xb8, 0x67, 0x1c, 0x5d, 0x7b, 0x19, 0x0a, 0xe1, 0x15, 0x39, 0xfb, 0x13, - 0x76, 0x86, 0xbe, 0x50, 0xa0, 0x7c, 0xc9, 0xd9, 0x9f, 0x5a, 0xfd, 0x11, 0x93, 0x8e, 0x2b, 0x80, - 0x57, 0x67, 0x5f, 0x31, 0xcc, 0xbf, 0xa6, 0x80, 0x08, 0x55, 0x6d, 0x72, 0x77, 0x55, 0x5a, 0xbd, - 0x0d, 0x05, 0x5f, 0x29, 0x50, 0x3a, 0xd5, 0x52, 0xb2, 0x6a, 0x69, 0x44, 0xc8, 0x0d, 0x8e, 0x4e, - 0xbf, 0xbd, 0x25, 0x0f, 0x52, 0x20, 0x0f, 0x01, 0xbc, 0xfa, 0x01, 0x77, 0x06, 0xa1, 0xbf, 0x08, - 0xc1, 0x35, 0x3c, 0xb4, 0x7a, 0xcc, 0x6f, 0xbb, 0x82, 0xb5, 0xd4, 0x61, 0x1c, 0xc9, 0x43, 0x8c, - 0x39, 0x1d, 0xb7, 0x6b, 0x3b, 0x3d, 0x19, 0x45, 0x21, 0xcc, 0x39, 0xd8, 0x4e, 0x97, 0x3d, 0xe2, - 0xec, 0x5a, 0xf6, 0x8f, 0x99, 0xd4, 0x6d, 0x1c, 0x49, 0x4c, 0x28, 0x05, 0x6e, 0x60, 0xf5, 0x29, - 0xeb, 0xb8, 0x5e, 0xd7, 0xaf, 0xe6, 0x90, 0x28, 0x86, 0xe3, 0x34, 0x5d, 0x2b, 0xb0, 0x9a, 0xea, - 0x24, 0x61, 0x90, 0x18, 0x8e, 0xdf, 0xf3, 0x94, 0x79, 0xbe, 0xed, 0x3a, 0x68, 0x8f, 0x02, 0x55, - 0x20, 0x21, 0x90, 0xf6, 0xf9, 0xf1, 0xb0, 0x62, 0xac, 0xa6, 0x29, 0xae, 0x79, 0xea, 0x78, 0xe0, - 0xba, 0x01, 0xf3, 0x50, 0xb0, 0x22, 0x9e, 0xa9, 0x61, 0xc8, 0x16, 0x54, 0xba, 0xac, 0x6b, 0x77, - 0xac, 0x80, 0x75, 0xef, 0xb9, 0xfd, 0xd1, 0xc0, 0xf1, 0xab, 0x25, 0xf4, 0xe6, 0x6a, 0xa8, 0xf2, - 0xad, 0x38, 0x01, 0x9d, 0xd8, 0x61, 0xfe, 0xc5, 0x80, 0xf9, 0x31, 0x2a, 0x72, 0x1b, 0x32, 0x7e, - 0xc7, 0x1d, 0x32, 0x19, 0xba, 0xcb, 0xd3, 0xd8, 0xd5, 0x5b, 0x9c, 0x8a, 0x0a, 0x62, 0x7e, 0x07, - 0xc7, 0x1a, 0x28, 0x5f, 0xc1, 0x35, 0xb9, 0x05, 0xe9, 0xe0, 0x6c, 0x28, 0xf2, 0xcb, 0x5c, 0xe3, - 0xa9, 0xa9, 0x8c, 0xda, 0x67, 0x43, 0x46, 0x91, 0xd4, 0xbc, 0x01, 0x19, 0x64, 0x4b, 0xf2, 0x90, - 0x6e, 0x1d, 0x6c, 0xec, 0x55, 0x66, 0x78, 0xb0, 0xd3, 0x66, 0x6b, 0xff, 0x1d, 0x7a, 0xaf, 0x89, - 0xf1, 0x9d, 0xe6, 0xe4, 0x04, 0x20, 0xdb, 0x6a, 0xd3, 0xed, 0xbd, 0xfb, 0x95, 0x19, 0xf3, 0x11, - 0xcc, 0x29, 0xef, 0x92, 0xa9, 0xed, 0x36, 0x64, 0x31, 0x7b, 0xa9, 0x08, 0xbf, 0x1e, 0xcf, 0x3f, - 0x82, 0x7a, 0x97, 0x05, 0x16, 0xb7, 0x10, 0x95, 0xb4, 0x64, 0x7d, 0x3c, 0xd5, 0x8d, 0x7b, 0xef, - 0x78, 0x9e, 0x33, 0xff, 0x91, 0x82, 0x2b, 0x09, 0x1c, 0xc7, 0x4b, 0x42, 0x21, 0x2a, 0x09, 0xab, - 0x30, 0xef, 0xb9, 0x6e, 0xd0, 0x62, 0xde, 0xa9, 0xdd, 0x61, 0x7b, 0x91, 0xca, 0xc6, 0xd1, 0xdc, - 0x3b, 0x39, 0x0a, 0xd9, 0x23, 0x9d, 0xa8, 0x10, 0x71, 0x24, 0x2f, 0x04, 0x18, 0x12, 0x6d, 0x7b, - 0xc0, 0xde, 0x71, 0xec, 0x47, 0x7b, 0x96, 0xe3, 0x62, 0x24, 0xa4, 0xe9, 0xe4, 0x07, 0xee, 0x55, - 0xdd, 0x28, 0x25, 0x89, 0xf4, 0xa2, 0x61, 0xc8, 0x73, 0x90, 0xf3, 0x65, 0xce, 0xc8, 0xa2, 0x06, - 0x2a, 0x91, 0x06, 0x04, 0x9e, 0x2a, 0x02, 0xf2, 0x02, 0xe4, 0xe5, 0x92, 0xc7, 0x44, 0x2a, 0x91, - 0x38, 0xa4, 0x20, 0x14, 0x4a, 0xbe, 0xb8, 0x1c, 0xcf, 0xe1, 0x7e, 0x35, 0x8f, 0x3b, 0xea, 0xe7, - 0xd9, 0xa5, 0xde, 0xd2, 0x36, 0x60, 0x92, 0xa2, 0x31, 0x1e, 0xb5, 0x43, 0x58, 0x98, 0x20, 0x49, - 0xc8, 0x63, 0xcf, 0xeb, 0x79, 0xac, 0xd8, 0x78, 0x42, 0x33, 0x6a, 0xb4, 0x59, 0x4f, 0x6f, 0x3b, - 0x50, 0xd2, 0x3f, 0x61, 0x1e, 0x1a, 0x5a, 0xce, 0x3d, 0x77, 0xe4, 0x04, 0xc8, 0x98, 0xe7, 0x21, - 0x85, 0xe0, 0x3a, 0x65, 0x9e, 0xe7, 0x7a, 0xe2, 0xb3, 0x28, 0x06, 0x1a, 0xc6, 0xfc, 0xb9, 0x01, - 0x39, 0xa9, 0x0f, 0xf2, 0x0c, 0x64, 0xf8, 0x46, 0xe5, 0x96, 0xe5, 0x98, 0xc2, 0xa8, 0xf8, 0x86, - 0x15, 0xd0, 0x0a, 0x3a, 0x0f, 0x59, 0x57, 0x72, 0x53, 0x20, 0x79, 0x0d, 0xc0, 0x0a, 0x02, 0xcf, - 0x3e, 0x1e, 0x05, 0x8c, 0x57, 0x14, 0xce, 0xe3, 0x5a, 0xc8, 0x43, 0xb6, 0x3b, 0xa7, 0xb7, 0xea, - 0x6f, 0xb1, 0xb3, 0x43, 0x7e, 0x1b, 0xaa, 0x91, 0xf3, 0x58, 0x4f, 0xf3, 0x63, 0xc8, 0x12, 0x64, - 0xf9, 0x41, 0xa1, 0x6f, 0x4a, 0x28, 0x31, 0x84, 0x13, 0xdd, 0x2b, 0x35, 0xcd, 0xbd, 0x6e, 0x42, - 0x59, 0x39, 0x13, 0x87, 0x7d, 0xe9, 0x88, 0x71, 0xe4, 0xd8, 0x2d, 0x32, 0x8f, 0x77, 0x8b, 0xdf, - 0x86, 0xb5, 0x5c, 0x06, 0x23, 0x8f, 0x28, 0xdb, 0xf1, 0x87, 0xac, 0x13, 0xb0, 0x6e, 0x5b, 0x05, - 0x3d, 0xd6, 0xbb, 0x31, 0x34, 0x79, 0x16, 0xe6, 0x42, 0xd4, 0xe6, 0x19, 0x3f, 0x7c, 0x16, 0xe5, - 0x1b, 0xc3, 0x92, 0x15, 0x28, 0x62, 0x76, 0xc7, 0xe2, 0xa6, 0x2a, 0xb7, 0x8e, 0xe2, 0x17, 0xed, - 0xb8, 0x83, 0x61, 0x9f, 0x05, 0xac, 0xfb, 0xa6, 0x7b, 0xec, 0xab, 0xda, 0x13, 0x43, 0x72, 0xbf, - 0xc1, 0x4d, 0x48, 0x21, 0x82, 0x2d, 0x42, 0x70, 0xb9, 0x23, 0x96, 0x42, 0x9c, 0x2c, 0x8a, 0x33, - 0x8e, 0x8e, 0xc9, 0x8d, 0x35, 0x1c, 0x6b, 0x90, 0x2e, 0x37, 0x62, 0xcd, 0x1e, 0x8f, 0x07, 0xae, - 0x1a, 0x5e, 0xd5, 0x55, 0x51, 0x5e, 0x54, 0xe9, 0x5c, 0x18, 0x5b, 0xa6, 0xeb, 0x45, 0xc8, 0x60, - 0x33, 0xa9, 0x6a, 0x3b, 0x02, 0x51, 0xe3, 0x91, 0x4a, 0x68, 0x3c, 0xd2, 0x61, 0xe3, 0x61, 0x7e, - 0x9c, 0x82, 0xa5, 0xe8, 0xa4, 0x58, 0x0f, 0xf0, 0xca, 0x64, 0x0f, 0x50, 0x1b, 0xcb, 0xa2, 0x9a, - 0x74, 0xdf, 0xf6, 0x01, 0xdf, 0x8c, 0x3e, 0xe0, 0xd3, 0x14, 0x5c, 0x0b, 0x8d, 0x83, 0x41, 0x17, - 0xb7, 0xea, 0xf7, 0x27, 0xad, 0x7a, 0x63, 0xd2, 0xaa, 0x62, 0xe3, 0xb7, 0xa6, 0xfd, 0x46, 0x99, - 0x76, 0x5d, 0xb5, 0xea, 0x22, 0xec, 0x64, 0x83, 0x54, 0x83, 0x7c, 0x60, 0xf5, 0x78, 0x07, 0x21, - 0x6a, 0x51, 0x81, 0x86, 0xb0, 0xf9, 0x26, 0x2c, 0x46, 0x3b, 0x0e, 0x1b, 0xe1, 0x9e, 0x06, 0x64, - 0x31, 0x79, 0xa8, 0xea, 0x95, 0x14, 0xd7, 0x87, 0x0d, 0xd1, 0x15, 0x4a, 0x4a, 0xf3, 0x35, 0x3d, - 0x25, 0xc9, 0x8f, 0x61, 0xa1, 0x31, 0xb4, 0x42, 0x43, 0x20, 0x1d, 0xf0, 0x89, 0x6c, 0x16, 0x85, - 0xc1, 0xb5, 0x39, 0xd4, 0xb2, 0x4c, 0xcc, 0xb7, 0xb0, 0xbf, 0x12, 0xe2, 0x86, 0xfd, 0x95, 0x00, - 0x2f, 0x4a, 0x6c, 0xe9, 0x84, 0xc4, 0x96, 0x89, 0x12, 0xdb, 0xcb, 0xf0, 0xe4, 0xc4, 0x89, 0xf2, - 0xf6, 0x3c, 0x99, 0x2b, 0xa4, 0x54, 0x59, 0x84, 0x30, 0x6f, 0x43, 0x5e, 0x6d, 0xc1, 0xab, 0x9c, - 0x85, 0x09, 0x17, 0xd7, 0xc9, 0xb3, 0x94, 0xb9, 0x03, 0x57, 0xc7, 0x8e, 0xd3, 0xd4, 0xbd, 0x36, - 0x7e, 0x60, 0xb1, 0xb1, 0x10, 0xb5, 0x4b, 0xf2, 0x8b, 0x2e, 0xc3, 0x1e, 0x64, 0xb0, 0xd0, 0x91, - 0x26, 0x94, 0x3d, 0xe6, 0xbb, 0x23, 0xaf, 0xc3, 0x5a, 0x5a, 0xb7, 0x11, 0x45, 0xac, 0x78, 0xd2, - 0x38, 0xbd, 0x55, 0xa7, 0x3a, 0x19, 0x8d, 0xef, 0x32, 0xf7, 0xa0, 0x74, 0x30, 0xf2, 0xa3, 0xa6, - 0xfa, 0x75, 0x28, 0x63, 0x5b, 0xe3, 0x6f, 0x9e, 0xb5, 0xe5, 0xbb, 0x41, 0x6a, 0x75, 0x4e, 0x73, - 0x46, 0x4e, 0xdd, 0xe4, 0x14, 0x94, 0x59, 0xbe, 0xeb, 0xd0, 0x38, 0xb9, 0xf9, 0x3b, 0x03, 0x2a, - 0x9c, 0x04, 0x8b, 0x9a, 0xb2, 0xe4, 0x8b, 0x61, 0xa7, 0xce, 0x2d, 0x5f, 0xda, 0x7c, 0x82, 0x4f, - 0xda, 0xff, 0xfc, 0xec, 0x46, 0xf9, 0xc0, 0x63, 0x56, 0xbf, 0xef, 0x76, 0x04, 0xb5, 0x6a, 0xd1, - 0xbf, 0x03, 0x29, 0xbb, 0x2b, 0x5a, 0x9f, 0xa9, 0xb4, 0x9c, 0x82, 0xdc, 0x01, 0x10, 0xf9, 0x67, - 0xcb, 0x0a, 0xac, 0x6a, 0xfa, 0x3c, 0x7a, 0x8d, 0xd0, 0xdc, 0x15, 0x22, 0x0a, 0x7d, 0x48, 0x11, - 0xef, 0x42, 0xee, 0x18, 0x1b, 0xb0, 0x2f, 0xad, 0x48, 0x45, 0x6f, 0xde, 0x04, 0x90, 0xaf, 0x11, - 0xbc, 0x8e, 0x2f, 0xc5, 0xa6, 0x92, 0x92, 0xba, 0x94, 0xf9, 0x3a, 0x14, 0x76, 0x6c, 0xe7, 0xa4, - 0xd5, 0xb7, 0x3b, 0x7c, 0x68, 0xca, 0xf4, 0x6d, 0xe7, 0x44, 0x9d, 0x75, 0x6d, 0xf2, 0x2c, 0x7e, - 0x46, 0x9d, 0x6f, 0xa0, 0x82, 0xd2, 0xfc, 0x99, 0x01, 0x84, 0x23, 0xd5, 0x78, 0x12, 0x55, 0x7e, - 0x11, 0x0a, 0x86, 0x1e, 0x0a, 0x55, 0xc8, 0xf5, 0x3c, 0x77, 0x34, 0xdc, 0x54, 0x21, 0xa2, 0x40, - 0x4e, 0xdf, 0xc7, 0xc7, 0x08, 0xd1, 0xdf, 0x09, 0xe0, 0x4b, 0x87, 0xce, 0x2f, 0x0c, 0xb8, 0xaa, - 0x09, 0xd1, 0x1a, 0x0d, 0x06, 0x96, 0x77, 0xf6, 0xff, 0x91, 0xe5, 0x0f, 0x06, 0x5c, 0x89, 0x29, - 0x24, 0x8a, 0x61, 0xe6, 0x07, 0xf6, 0x80, 0xe7, 0x47, 0x94, 0x24, 0x4f, 0x23, 0x44, 0xbc, 0xcd, - 0x17, 0x9d, 0xa1, 0xd6, 0xe6, 0x3f, 0x0b, 0x73, 0xe8, 0xce, 0xad, 0x90, 0x44, 0x88, 0x36, 0x86, - 0x25, 0xf5, 0x68, 0x88, 0x4c, 0xa3, 0x05, 0x17, 0x63, 0x4d, 0xfe, 0xc4, 0x08, 0xf9, 0x3d, 0x28, - 0x51, 0xeb, 0xc3, 0x37, 0x6c, 0x3f, 0x70, 0x7b, 0x9e, 0x35, 0xe0, 0x4e, 0x72, 0x3c, 0xea, 0x9c, - 0x30, 0x31, 0x69, 0xa4, 0xa9, 0x84, 0xf8, 0xdd, 0x3b, 0x9a, 0x64, 0x02, 0x30, 0xdf, 0x84, 0xbc, - 0x6a, 0x93, 0x13, 0x26, 0x9f, 0x17, 0xe2, 0x93, 0xcf, 0x52, 0x7c, 0xda, 0x7a, 0x7b, 0x87, 0x8f, - 0x37, 0x76, 0x47, 0x65, 0xa3, 0x5f, 0x1b, 0x50, 0xd4, 0x44, 0x24, 0x9b, 0xb0, 0xd0, 0xb7, 0x02, - 0xe6, 0x74, 0xce, 0x8e, 0x1e, 0x2a, 0xf1, 0xa4, 0x57, 0x46, 0x33, 0x94, 0x2e, 0x3b, 0xad, 0x48, - 0xfa, 0xe8, 0x36, 0xdf, 0x85, 0xac, 0xcf, 0x3c, 0x5b, 0x86, 0xb7, 0x9e, 0xc1, 0xc2, 0xee, 0x5e, - 0x12, 0xf0, 0x8b, 0x8b, 0x7c, 0x21, 0x15, 0x2b, 0x21, 0xf3, 0xef, 0x71, 0xef, 0x96, 0x8e, 0x35, - 0x39, 0x94, 0x5d, 0x60, 0xad, 0xd9, 0x44, 0x6b, 0x45, 0xf2, 0xa5, 0x2e, 0x92, 0xaf, 0x02, 0xa9, - 0xe1, 0xdd, 0xbb, 0x72, 0xa4, 0xe1, 0x4b, 0x81, 0xb9, 0x83, 0x8e, 0x87, 0x98, 0x3b, 0x02, 0xb3, - 0x2e, 0xfb, 0x78, 0xbe, 0x44, 0xcc, 0x9d, 0x75, 0xd9, 0xb0, 0xf3, 0xa5, 0xf9, 0x2e, 0xd4, 0x92, - 0xe2, 0x44, 0xba, 0xe8, 0x5d, 0x28, 0xf8, 0x88, 0xb2, 0xd9, 0x64, 0x0a, 0x48, 0xd8, 0x17, 0x51, - 0x9b, 0xbf, 0x31, 0xa0, 0x1c, 0x33, 0x6c, 0xac, 0x12, 0x65, 0x64, 0x25, 0x2a, 0x81, 0xe1, 0xa0, - 0x32, 0x52, 0xd4, 0x70, 0x38, 0xf4, 0x00, 0xf5, 0x6d, 0x50, 0xe3, 0x01, 0x87, 0x7c, 0xf9, 0xea, - 0x6a, 0xf8, 0x1c, 0x3a, 0xc6, 0xcb, 0xe5, 0xa9, 0x71, 0xcc, 0xa1, 0xae, 0xbc, 0x98, 0xd1, 0xc5, - 0x19, 0x52, 0x3c, 0xf0, 0xe6, 0x90, 0xb7, 0x7a, 0xbd, 0x25, 0x90, 0x3e, 0xb1, 0x9d, 0x2e, 0x76, - 0x47, 0x19, 0x8a, 0x6b, 0x93, 0x89, 0x07, 0x49, 0x29, 0x38, 0x4f, 0xb3, 0xbc, 0xf5, 0xf1, 0x98, - 0x3f, 0xea, 0x07, 0xed, 0xa8, 0x50, 0x6a, 0x18, 0xde, 0x6a, 0x08, 0x48, 0xba, 0x4d, 0x2d, 0x31, - 0x86, 0x90, 0x82, 0x4a, 0x4a, 0x9e, 0x05, 0x17, 0x26, 0xbe, 0x72, 0x37, 0xe9, 0x5b, 0xc7, 0xac, - 0xaf, 0xf5, 0x0a, 0x11, 0x82, 0xcb, 0x81, 0xc0, 0xa1, 0x56, 0x9b, 0x35, 0x0c, 0x59, 0x83, 0xd9, - 0x40, 0xb9, 0xc6, 0x8d, 0xe9, 0x32, 0x1c, 0xb8, 0xb6, 0x13, 0xd0, 0xd9, 0xc0, 0xe7, 0x31, 0xb4, - 0x94, 0xfc, 0x19, 0x8d, 0x61, 0x4b, 0x21, 0xca, 0x14, 0xd7, 0xdc, 0x3b, 0x4e, 0xad, 0x3e, 0x1e, - 0x6c, 0x50, 0xbe, 0xe4, 0x53, 0x21, 0x7b, 0xc4, 0x06, 0xc3, 0xbe, 0xe5, 0xb5, 0xe5, 0x0b, 0x52, - 0x0a, 0x7f, 0x54, 0x18, 0x47, 0x93, 0xe7, 0xa0, 0xa2, 0x50, 0xea, 0x45, 0x59, 0x3a, 0xe7, 0x04, - 0xde, 0x6c, 0xc1, 0x15, 0x7c, 0x1c, 0xde, 0x76, 0xfc, 0xc0, 0x72, 0x82, 0xf3, 0xb3, 0x72, 0x98, - 0x65, 0x65, 0xa6, 0x89, 0x65, 0x59, 0x11, 0x9b, 0x98, 0x65, 0x1f, 0xc1, 0x62, 0x9c, 0xa9, 0x74, - 0xe1, 0x7a, 0x18, 0x53, 0xc2, 0x7f, 0xa3, 0xb4, 0x23, 0x29, 0x5b, 0xf8, 0x35, 0x0c, 0xac, 0xc7, - 0x7f, 0x76, 0xfb, 0xa9, 0x01, 0xe5, 0x18, 0x2f, 0x72, 0x17, 0xb2, 0x68, 0xb6, 0xc9, 0x98, 0x99, - 0x7c, 0x4f, 0x90, 0xaf, 0xf9, 0x72, 0x43, 0xbc, 0x35, 0x33, 0x64, 0x32, 0x24, 0x37, 0xa0, 0x38, - 0xf4, 0xdc, 0xc1, 0x91, 0xe4, 0x2a, 0xde, 0xde, 0x80, 0xa3, 0x76, 0x10, 0x63, 0xfe, 0x31, 0x05, - 0x0b, 0x78, 0x7d, 0x6a, 0x39, 0x3d, 0x76, 0x29, 0x1a, 0xc5, 0x29, 0x21, 0x60, 0x43, 0x69, 0x46, - 0x5c, 0xc7, 0x7f, 0x07, 0xca, 0x8d, 0xff, 0x0e, 0xa4, 0x4d, 0x56, 0xf9, 0x73, 0x26, 0xab, 0xc2, - 0x85, 0x93, 0x15, 0x24, 0x4d, 0x56, 0xda, 0x3c, 0x53, 0x8c, 0xcf, 0x33, 0xfa, 0xcc, 0x55, 0x1a, - 0x9b, 0xb9, 0xd4, 0xac, 0x53, 0x9e, 0x3a, 0xeb, 0xcc, 0x7d, 0xa9, 0x59, 0x67, 0xfe, 0x71, 0x67, - 0x1d, 0xac, 0xef, 0xd2, 0xf5, 0xfd, 0x6a, 0x45, 0xdc, 0x39, 0x44, 0x98, 0x3e, 0x10, 0xdd, 0x60, - 0xd2, 0x5b, 0x9f, 0x1f, 0xf3, 0xd6, 0x2b, 0x51, 0x91, 0xb4, 0x07, 0xec, 0x2b, 0xbb, 0xea, 0x4f, - 0x20, 0xdf, 0x94, 0x12, 0x5c, 0xbe, 0x93, 0x3e, 0x0d, 0x25, 0x9e, 0x46, 0xfc, 0xc0, 0x1a, 0x0c, - 0x8f, 0x06, 0xc2, 0x4b, 0x53, 0xb4, 0x18, 0xe2, 0x76, 0x7d, 0x73, 0x03, 0xb2, 0x2d, 0x6b, 0x30, - 0xec, 0x4f, 0x12, 0xcf, 0x4e, 0x10, 0x47, 0xa7, 0x18, 0xda, 0x29, 0xe6, 0x27, 0x06, 0x40, 0xa4, - 0x8b, 0xaf, 0x72, 0x8b, 0x35, 0xc8, 0xf9, 0x28, 0x8c, 0x6a, 0x07, 0xe6, 0x23, 0xf5, 0x21, 0x5e, - 0xd2, 0x2b, 0xaa, 0x0b, 0xa3, 0x90, 0xdc, 0xd1, 0x2d, 0x9e, 0x1e, 0x2b, 0xe1, 0x4a, 0xf1, 0x92, - 0x6b, 0x44, 0xf9, 0xdc, 0xfb, 0x30, 0x3f, 0x36, 0xac, 0x90, 0x12, 0xe4, 0xf7, 0xf6, 0x8f, 0x9a, - 0x94, 0xee, 0xd3, 0xca, 0x0c, 0xb9, 0x02, 0xf3, 0xbb, 0x1b, 0xef, 0x1d, 0xed, 0x6c, 0x1f, 0x36, - 0x8f, 0xda, 0x74, 0xe3, 0x5e, 0xb3, 0x55, 0x31, 0x38, 0x12, 0xd7, 0x47, 0xed, 0xfd, 0xfd, 0xa3, - 0x9d, 0x0d, 0x7a, 0xbf, 0x59, 0x99, 0x25, 0x0b, 0x50, 0x7e, 0x67, 0xef, 0xad, 0xbd, 0xfd, 0x77, - 0xf7, 0xe4, 0xe6, 0x54, 0xe3, 0x97, 0x06, 0x64, 0x39, 0x7b, 0xe6, 0x91, 0x1f, 0x40, 0x21, 0x1c, - 0x79, 0xc8, 0xd5, 0xd8, 0xa4, 0xa4, 0x8f, 0x41, 0xb5, 0x27, 0x62, 0x9f, 0x94, 0x73, 0x9a, 0x33, - 0x64, 0x03, 0x8a, 0x21, 0xf1, 0x61, 0xe3, 0x7f, 0x61, 0xd1, 0xf8, 0xb7, 0x01, 0x15, 0xe9, 0x97, - 0xf7, 0x99, 0xc3, 0x3c, 0x2b, 0x70, 0x43, 0xc1, 0x70, 0x5e, 0x19, 0xe3, 0xaa, 0x0f, 0x3f, 0xd3, - 0x05, 0xdb, 0x06, 0xb8, 0xcf, 0x02, 0xd5, 0x2b, 0x5e, 0x4b, 0x2e, 0x8e, 0x82, 0xc7, 0xf5, 0x29, - 0x95, 0x53, 0xb1, 0xba, 0x0f, 0x10, 0x05, 0x26, 0x89, 0x6a, 0xfd, 0x44, 0x7a, 0xad, 0x5d, 0x4b, - 0xfc, 0x16, 0xde, 0xf4, 0xf7, 0x69, 0xc8, 0xf1, 0x0f, 0x36, 0xf3, 0xc8, 0x1b, 0x50, 0xfe, 0xa1, - 0xed, 0x74, 0xc3, 0x1f, 0x83, 0xc9, 0xd5, 0xa4, 0xdf, 0xa0, 0x05, 0xdb, 0xda, 0xf4, 0x9f, 0xa7, - 0xd1, 0x04, 0x25, 0xf5, 0xf3, 0x52, 0x87, 0x39, 0x01, 0x99, 0xf2, 0x9b, 0x66, 0xed, 0xc9, 0x09, - 0x7c, 0xc8, 0xa2, 0x09, 0x45, 0xed, 0xf7, 0x52, 0x5d, 0x5b, 0x13, 0xbf, 0xa2, 0x9e, 0xc7, 0xe6, - 0x3e, 0x40, 0xf4, 0x9a, 0x42, 0xce, 0x79, 0x57, 0xad, 0x5d, 0x4b, 0xfc, 0x16, 0x32, 0x7a, 0x4b, - 0x5d, 0x49, 0x3c, 0xcb, 0x9c, 0xcb, 0xea, 0xa9, 0xc4, 0x67, 0x1e, 0x8d, 0xd9, 0x21, 0xcc, 0x8f, - 0xbd, 0x62, 0x90, 0x8b, 0x1e, 0x07, 0x6b, 0x2b, 0xd3, 0x09, 0x42, 0xbe, 0x3f, 0xd2, 0xde, 0x8e, - 0xd4, 0xeb, 0xc8, 0xc5, 0x9c, 0xcd, 0x69, 0x04, 0xba, 0xcc, 0x8d, 0xbf, 0xa5, 0xa1, 0xd2, 0x0a, - 0x3c, 0x66, 0x0d, 0x6c, 0xa7, 0xa7, 0x5c, 0xe6, 0x35, 0xc8, 0xca, 0xc2, 0xf7, 0xb8, 0x26, 0x5e, - 0x37, 0x78, 0x3c, 0x5c, 0x8a, 0x6d, 0xd6, 0x0d, 0xb2, 0x7b, 0x89, 0xd6, 0x59, 0x37, 0xc8, 0x7b, - 0x5f, 0x8f, 0x7d, 0xd6, 0x0d, 0xf2, 0xfe, 0xd7, 0x67, 0xa1, 0x75, 0x83, 0x1c, 0xc0, 0x82, 0xcc, - 0x15, 0x97, 0x92, 0x1d, 0xd6, 0x0d, 0x72, 0x08, 0x57, 0x74, 0x8e, 0xb2, 0x85, 0x24, 0xd7, 0xe3, - 0xfb, 0xe2, 0x4d, 0xb2, 0xa6, 0xe1, 0xa4, 0x6e, 0x97, 0xf3, 0x6d, 0xfc, 0xc9, 0x80, 0x9c, 0xca, - 0x84, 0x47, 0x89, 0xd3, 0xaa, 0x79, 0xde, 0x0c, 0x27, 0x0f, 0x7a, 0xe6, 0x5c, 0x9a, 0x4b, 0xcf, - 0x96, 0x9b, 0xd5, 0x8f, 0x3e, 0x5f, 0x36, 0x3e, 0xf9, 0x7c, 0xd9, 0xf8, 0xd7, 0xe7, 0xcb, 0xc6, - 0xaf, 0xbe, 0x58, 0x9e, 0xf9, 0xe4, 0x8b, 0xe5, 0x99, 0x4f, 0xbf, 0x58, 0x9e, 0x39, 0xce, 0xe2, - 0x7f, 0x3b, 0xbd, 0xf4, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdc, 0xc4, 0xa8, 0xe6, 0x6e, 0x25, - 0x00, 0x00, + // 2837 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x3a, 0xcd, 0x6f, 0x1b, 0xc7, + 0xf5, 0x5a, 0xf1, 0xfb, 0x91, 0x94, 0xa8, 0xb1, 0xa2, 0xd0, 0xb4, 0x23, 0x2b, 0x1b, 0x23, 0x3f, + 0xfd, 0xf2, 0x41, 0xc9, 0x8c, 0x8d, 0xc4, 0x49, 0x9b, 0x42, 0xb2, 0x58, 0x47, 0x89, 0xbe, 0x32, + 0x64, 0x94, 0x20, 0x08, 0x20, 0xac, 0xc8, 0x31, 0xbd, 0x10, 0xb9, 0xcb, 0xec, 0x2e, 0x15, 0xab, + 0x87, 0x02, 0x2d, 0xd0, 0x43, 0x81, 0x1e, 0x7a, 0x68, 0x0f, 0x3d, 0xf6, 0x54, 0xf4, 0xd4, 0x43, + 0xfb, 0x1f, 0x14, 0x28, 0x02, 0x14, 0x0d, 0x02, 0xf4, 0x12, 0xf4, 0x10, 0x14, 0xc9, 0xa1, 0xfd, + 0x33, 0x8a, 0x79, 0x33, 0xb3, 0x3b, 0x4b, 0x2e, 0xa5, 0xb8, 0x51, 0xd0, 0x1c, 0x72, 0xe2, 0xcc, + 0x9b, 0x37, 0x6f, 0xde, 0xbc, 0xef, 0x37, 0x4b, 0x78, 0x72, 0x78, 0xd2, 0x5b, 0x0b, 0xd8, 0x60, + 0xe8, 0x0e, 0x8f, 0xc5, 0x6f, 0x7d, 0xe8, 0xb9, 0x81, 0x4b, 0x72, 0x12, 0x58, 0x5b, 0xea, 0xb8, + 0x83, 0x81, 0xeb, 0xac, 0x9d, 0xde, 0x5a, 0x13, 0x23, 0x81, 0x50, 0x7b, 0xb1, 0x67, 0x07, 0x0f, + 0x47, 0xc7, 0xf5, 0x8e, 0x3b, 0x58, 0xeb, 0xb9, 0x3d, 0x77, 0x0d, 0xc1, 0xc7, 0xa3, 0x07, 0x38, + 0xc3, 0x09, 0x8e, 0x24, 0xfa, 0x62, 0xe0, 0x59, 0x1d, 0xc6, 0xa9, 0xe0, 0x40, 0x40, 0xcd, 0x3f, + 0x19, 0x50, 0x69, 0xf3, 0xf9, 0xe6, 0xd9, 0xf6, 0x16, 0x65, 0x1f, 0x8e, 0x98, 0x1f, 0x90, 0x2a, + 0xe4, 0x10, 0x67, 0x7b, 0xab, 0x6a, 0xac, 0x18, 0xab, 0x25, 0xaa, 0xa6, 0x64, 0x19, 0xe0, 0xb8, + 0xef, 0x76, 0x4e, 0x5a, 0x81, 0xe5, 0x05, 0xd5, 0xd9, 0x15, 0x63, 0xb5, 0x40, 0x35, 0x08, 0xa9, + 0x41, 0x1e, 0x67, 0x4d, 0xa7, 0x5b, 0x4d, 0xe1, 0x6a, 0x38, 0x27, 0xd7, 0xa1, 0xf0, 0xe1, 0x88, + 0x79, 0x67, 0xbb, 0x6e, 0x97, 0x55, 0x33, 0xb8, 0x18, 0x01, 0xc8, 0x0b, 0xb0, 0x60, 0xf5, 0xfb, + 0xee, 0x47, 0x07, 0x96, 0x17, 0xd8, 0x56, 0x1f, 0x79, 0xaa, 0x66, 0x57, 0x8c, 0xd5, 0x3c, 0x9d, + 0x5c, 0x30, 0xff, 0x6d, 0xc0, 0x82, 0xc6, 0xb6, 0x3f, 0x74, 0x1d, 0x9f, 0x91, 0x9b, 0x90, 0x41, + 0x46, 0x91, 0xeb, 0x62, 0x63, 0xae, 0x2e, 0x45, 0x58, 0x47, 0x54, 0x2a, 0x16, 0xc9, 0x4b, 0x90, + 0x1b, 0xb0, 0xc0, 0xb3, 0x3b, 0x3e, 0x5e, 0xa0, 0xd8, 0xb8, 0x1a, 0xc7, 0xe3, 0x24, 0x77, 0x05, + 0x02, 0x55, 0x98, 0xe4, 0x2e, 0x64, 0xfd, 0xc0, 0x0a, 0x46, 0x3e, 0x5e, 0x6b, 0xae, 0xf1, 0xf4, + 0xe4, 0x1e, 0xc5, 0x46, 0xbd, 0x85, 0x88, 0x54, 0x6e, 0xe0, 0xd2, 0x1c, 0x30, 0xdf, 0xb7, 0x7a, + 0xac, 0x9a, 0xc6, 0x5b, 0xab, 0xa9, 0xf9, 0x0c, 0x64, 0x05, 0x2e, 0x29, 0x41, 0xfe, 0xde, 0xfe, + 0xee, 0xc1, 0x4e, 0xb3, 0xdd, 0xac, 0xcc, 0x90, 0x22, 0xe4, 0x0e, 0x36, 0x68, 0x7b, 0x7b, 0x63, + 0xa7, 0x62, 0x98, 0x44, 0x53, 0x90, 0x64, 0xcb, 0xfc, 0x64, 0x16, 0xca, 0x2d, 0x66, 0x79, 0x9d, + 0x87, 0x4a, 0x65, 0xaf, 0x42, 0xba, 0x6d, 0xf5, 0xfc, 0xaa, 0xb1, 0x92, 0x5a, 0x2d, 0x36, 0x56, + 0x42, 0xee, 0x62, 0x58, 0x75, 0x8e, 0xd2, 0x74, 0x02, 0xef, 0x6c, 0x33, 0xfd, 0xf1, 0xe7, 0x37, + 0x66, 0x28, 0xee, 0x21, 0x37, 0xa1, 0xbc, 0x6b, 0x3b, 0x5b, 0x23, 0xcf, 0x0a, 0x6c, 0xd7, 0xd9, + 0x15, 0x62, 0x29, 0xd3, 0x38, 0x10, 0xb1, 0xac, 0x47, 0x1a, 0x56, 0x4a, 0x62, 0xe9, 0x40, 0xb2, + 0x08, 0x99, 0x1d, 0x7b, 0x60, 0x07, 0x78, 0xd5, 0x32, 0x15, 0x13, 0x0e, 0xf5, 0xd1, 0x62, 0x32, + 0x02, 0x8a, 0x13, 0x52, 0x81, 0x14, 0x73, 0xba, 0xa8, 0xe4, 0x32, 0xe5, 0x43, 0x8e, 0xf7, 0x36, + 0xb7, 0x88, 0x6a, 0x1e, 0x05, 0x25, 0x26, 0x64, 0x15, 0xe6, 0x5b, 0x43, 0xcb, 0xf1, 0x0f, 0x98, + 0xc7, 0x7f, 0x5b, 0x2c, 0xa8, 0x16, 0x70, 0xcf, 0x38, 0xb8, 0xf6, 0x32, 0x14, 0xc2, 0x2b, 0x72, + 0xf2, 0x27, 0xec, 0x0c, 0x6d, 0xa1, 0x40, 0xf9, 0x90, 0x93, 0x3f, 0xb5, 0xfa, 0x23, 0x26, 0x0d, + 0x57, 0x4c, 0x5e, 0x9d, 0x7d, 0xc5, 0x30, 0xff, 0x92, 0x02, 0x22, 0x44, 0xb5, 0xc9, 0xcd, 0x55, + 0x49, 0xf5, 0x36, 0x14, 0x7c, 0x25, 0x40, 0x69, 0x54, 0x4b, 0xc9, 0xa2, 0xa5, 0x11, 0x22, 0x57, + 0x38, 0x1a, 0xfd, 0xf6, 0x96, 0x3c, 0x48, 0x4d, 0xb9, 0x0b, 0xe0, 0xd5, 0x0f, 0xb8, 0x31, 0x08, + 0xf9, 0x45, 0x00, 0x2e, 0xe1, 0xa1, 0xd5, 0x63, 0x7e, 0xdb, 0x15, 0xa4, 0xa5, 0x0c, 0xe3, 0x40, + 0xee, 0x62, 0xcc, 0xe9, 0xb8, 0x5d, 0xdb, 0xe9, 0x49, 0x2f, 0x0a, 0xe7, 0x9c, 0x82, 0xed, 0x74, + 0xd9, 0x23, 0x4e, 0xae, 0x65, 0xff, 0x88, 0x49, 0xd9, 0xc6, 0x81, 0xc4, 0x84, 0x52, 0xe0, 0x06, + 0x56, 0x9f, 0xb2, 0x8e, 0xeb, 0x75, 0xfd, 0x6a, 0x0e, 0x91, 0x62, 0x30, 0x8e, 0xd3, 0xb5, 0x02, + 0xab, 0xa9, 0x4e, 0x12, 0x0a, 0x89, 0xc1, 0xf8, 0x3d, 0x4f, 0x99, 0xe7, 0xdb, 0xae, 0x83, 0xfa, + 0x28, 0x50, 0x35, 0x25, 0x04, 0xd2, 0x3e, 0x3f, 0x1e, 0x56, 0x8c, 0xd5, 0x34, 0xc5, 0x31, 0x0f, + 0x1d, 0x0f, 0x5c, 0x37, 0x60, 0x1e, 0x32, 0x56, 0xc4, 0x33, 0x35, 0x08, 0xd9, 0x82, 0x4a, 0x97, + 0x75, 0xed, 0x8e, 0x15, 0xb0, 0xee, 0x3d, 0xb7, 0x3f, 0x1a, 0x38, 0x7e, 0xb5, 0x84, 0xd6, 0x5c, + 0x0d, 0x45, 0xbe, 0x15, 0x47, 0xa0, 0x13, 0x3b, 0xcc, 0x3f, 0x1b, 0x30, 0x3f, 0x86, 0x45, 0x6e, + 0x43, 0xc6, 0xef, 0xb8, 0x43, 0x26, 0x5d, 0x77, 0x79, 0x1a, 0xb9, 0x7a, 0x8b, 0x63, 0x51, 0x81, + 0xcc, 0xef, 0xe0, 0x58, 0x03, 0x65, 0x2b, 0x38, 0x26, 0xb7, 0x20, 0x1d, 0x9c, 0x0d, 0x45, 0x7c, + 0x99, 0x6b, 0x3c, 0x35, 0x95, 0x50, 0xfb, 0x6c, 0xc8, 0x28, 0xa2, 0x9a, 0x37, 0x20, 0x83, 0x64, + 0x49, 0x1e, 0xd2, 0xad, 0x83, 0x8d, 0xbd, 0xca, 0x0c, 0x77, 0x76, 0xda, 0x6c, 0xed, 0xbf, 0x43, + 0xef, 0x35, 0xd1, 0xbf, 0xd3, 0x1c, 0x9d, 0x00, 0x64, 0x5b, 0x6d, 0xba, 0xbd, 0x77, 0xbf, 0x32, + 0x63, 0x3e, 0x82, 0x39, 0x65, 0x5d, 0x32, 0xb4, 0xdd, 0x86, 0x2c, 0x46, 0x2f, 0xe5, 0xe1, 0xd7, + 0xe3, 0xf1, 0x47, 0x60, 0xef, 0xb2, 0xc0, 0xe2, 0x1a, 0xa2, 0x12, 0x97, 0xac, 0x8f, 0x87, 0xba, + 0x71, 0xeb, 0x1d, 0x8f, 0x73, 0xe6, 0xdf, 0x53, 0x70, 0x25, 0x81, 0xe2, 0x78, 0x4a, 0x28, 0x44, + 0x29, 0x61, 0x15, 0xe6, 0x3d, 0xd7, 0x0d, 0x5a, 0xcc, 0x3b, 0xb5, 0x3b, 0x6c, 0x2f, 0x12, 0xd9, + 0x38, 0x98, 0x5b, 0x27, 0x07, 0x21, 0x79, 0xc4, 0x13, 0x19, 0x22, 0x0e, 0xe4, 0x89, 0x00, 0x5d, + 0xa2, 0x6d, 0x0f, 0xd8, 0x3b, 0x8e, 0xfd, 0x68, 0xcf, 0x72, 0x5c, 0xf4, 0x84, 0x34, 0x9d, 0x5c, + 0xe0, 0x56, 0xd5, 0x8d, 0x42, 0x92, 0x08, 0x2f, 0x1a, 0x84, 0x3c, 0x07, 0x39, 0x5f, 0xc6, 0x8c, + 0x2c, 0x4a, 0xa0, 0x12, 0x49, 0x40, 0xc0, 0xa9, 0x42, 0x20, 0x2f, 0x40, 0x5e, 0x0e, 0xb9, 0x4f, + 0xa4, 0x12, 0x91, 0x43, 0x0c, 0x42, 0xa1, 0xe4, 0x8b, 0xcb, 0xf1, 0x18, 0xee, 0x57, 0xf3, 0xb8, + 0xa3, 0x7e, 0x9e, 0x5e, 0xea, 0x2d, 0x6d, 0x03, 0x06, 0x29, 0x1a, 0xa3, 0x51, 0x3b, 0x84, 0x85, + 0x09, 0x94, 0x84, 0x38, 0xf6, 0xbc, 0x1e, 0xc7, 0x8a, 0x8d, 0x27, 0x34, 0xa5, 0x46, 0x9b, 0xf5, + 0xf0, 0xb6, 0x03, 0x25, 0x7d, 0x09, 0xe3, 0xd0, 0xd0, 0x72, 0xee, 0xb9, 0x23, 0x27, 0x40, 0xc2, + 0x3c, 0x0e, 0x29, 0x00, 0x97, 0x29, 0xf3, 0x3c, 0xd7, 0x13, 0xcb, 0x22, 0x19, 0x68, 0x10, 0xf3, + 0x67, 0x06, 0xe4, 0xa4, 0x3c, 0xc8, 0x33, 0x90, 0xe1, 0x1b, 0x95, 0x59, 0x96, 0x63, 0x02, 0xa3, + 0x62, 0x0d, 0x33, 0xa0, 0x15, 0x74, 0x1e, 0xb2, 0xae, 0xa4, 0xa6, 0xa6, 0xe4, 0x35, 0x00, 0x2b, + 0x08, 0x3c, 0xfb, 0x78, 0x14, 0x30, 0x9e, 0x51, 0x38, 0x8d, 0x6b, 0x21, 0x0d, 0x59, 0xee, 0x9c, + 0xde, 0xaa, 0xbf, 0xc5, 0xce, 0x0e, 0xf9, 0x6d, 0xa8, 0x86, 0xce, 0x7d, 0x3d, 0xcd, 0x8f, 0x21, + 0x4b, 0x90, 0xe5, 0x07, 0x85, 0xb6, 0x29, 0x67, 0x89, 0x2e, 0x9c, 0x68, 0x5e, 0xa9, 0x69, 0xe6, + 0x75, 0x13, 0xca, 0xca, 0x98, 0xf8, 0xdc, 0x97, 0x86, 0x18, 0x07, 0x8e, 0xdd, 0x22, 0xf3, 0x78, + 0xb7, 0xf8, 0x4d, 0x98, 0xcb, 0xa5, 0x33, 0x72, 0x8f, 0xb2, 0x1d, 0x7f, 0xc8, 0x3a, 0x01, 0xeb, + 0xb6, 0x95, 0xd3, 0x63, 0xbe, 0x1b, 0x03, 0x93, 0x67, 0x61, 0x2e, 0x04, 0x6d, 0x9e, 0xf1, 0xc3, + 0x67, 0x91, 0xbf, 0x31, 0x28, 0x59, 0x81, 0x22, 0x46, 0x77, 0x4c, 0x6e, 0x2a, 0x73, 0xeb, 0x20, + 0x7e, 0xd1, 0x8e, 0x3b, 0x18, 0xf6, 0x59, 0xc0, 0xba, 0x6f, 0xba, 0xc7, 0xbe, 0xca, 0x3d, 0x31, + 0x20, 0xb7, 0x1b, 0xdc, 0x84, 0x18, 0xc2, 0xd9, 0x22, 0x00, 0xe7, 0x3b, 0x22, 0x29, 0xd8, 0xc9, + 0x22, 0x3b, 0xe3, 0xe0, 0x18, 0xdf, 0x98, 0xc3, 0x31, 0x07, 0xe9, 0x7c, 0x23, 0xd4, 0xec, 0x71, + 0x7f, 0xe0, 0xa2, 0xe1, 0x59, 0x5d, 0x25, 0xe5, 0x45, 0x15, 0xce, 0x85, 0xb2, 0x65, 0xb8, 0x5e, + 0x84, 0x0c, 0x16, 0x93, 0x2a, 0xb7, 0xe3, 0x24, 0x2a, 0x3c, 0x52, 0x09, 0x85, 0x47, 0x3a, 0x2c, + 0x3c, 0xcc, 0x4f, 0x52, 0xb0, 0x14, 0x9d, 0x14, 0xab, 0x01, 0x5e, 0x99, 0xac, 0x01, 0x6a, 0x63, + 0x51, 0x54, 0xe3, 0xee, 0xbb, 0x3a, 0xe0, 0xdb, 0x51, 0x07, 0x7c, 0x96, 0x82, 0x6b, 0xa1, 0x72, + 0xd0, 0xe9, 0xe2, 0x5a, 0xfd, 0xfe, 0xa4, 0x56, 0x6f, 0x4c, 0x6a, 0x55, 0x6c, 0xfc, 0x4e, 0xb5, + 0xdf, 0x2a, 0xd5, 0xae, 0xab, 0x52, 0x5d, 0xb8, 0x9d, 0x2c, 0x90, 0x6a, 0x90, 0x0f, 0xac, 0x1e, + 0xaf, 0x20, 0x44, 0x2e, 0x2a, 0xd0, 0x70, 0x6e, 0xbe, 0x09, 0x8b, 0xd1, 0x8e, 0xc3, 0x46, 0xb8, + 0xa7, 0x01, 0x59, 0x0c, 0x1e, 0x2a, 0x7b, 0x25, 0xf9, 0xf5, 0x61, 0x43, 0x54, 0x85, 0x12, 0xd3, + 0x7c, 0x4d, 0x0f, 0x49, 0x72, 0x31, 0x4c, 0x34, 0x86, 0x96, 0x68, 0x08, 0xa4, 0x03, 0xde, 0x91, + 0xcd, 0x22, 0x33, 0x38, 0x36, 0x87, 0x5a, 0x94, 0x89, 0xd9, 0x16, 0xd6, 0x57, 0x82, 0xdd, 0xb0, + 0xbe, 0x12, 0xd3, 0x8b, 0x02, 0x5b, 0x3a, 0x21, 0xb0, 0x65, 0xa2, 0xc0, 0xf6, 0x32, 0x3c, 0x39, + 0x71, 0xa2, 0xbc, 0x3d, 0x0f, 0xe6, 0x0a, 0x28, 0x45, 0x16, 0x01, 0xcc, 0xdb, 0x90, 0x57, 0x5b, + 0xf0, 0x2a, 0x67, 0x61, 0xc0, 0xc5, 0x71, 0x72, 0x2f, 0x65, 0xee, 0xc0, 0xd5, 0xb1, 0xe3, 0x34, + 0x71, 0xaf, 0x8d, 0x1f, 0x58, 0x6c, 0x2c, 0x44, 0xe5, 0x92, 0x5c, 0xd1, 0x79, 0xd8, 0x83, 0x0c, + 0x26, 0x3a, 0xd2, 0x84, 0xb2, 0xc7, 0x7c, 0x77, 0xe4, 0x75, 0x58, 0x4b, 0xab, 0x36, 0x22, 0x8f, + 0x15, 0x4f, 0x1a, 0xa7, 0xb7, 0xea, 0x54, 0x47, 0xa3, 0xf1, 0x5d, 0xe6, 0x1e, 0x94, 0x0e, 0x46, + 0x7e, 0x54, 0x54, 0xbf, 0x0e, 0x65, 0x2c, 0x6b, 0xfc, 0xcd, 0xb3, 0xb6, 0x7c, 0x37, 0x48, 0xad, + 0xce, 0x69, 0xc6, 0xc8, 0xb1, 0x9b, 0x1c, 0x83, 0x32, 0xcb, 0x77, 0x1d, 0x1a, 0x47, 0x37, 0x7f, + 0x6b, 0x40, 0x85, 0xa3, 0x60, 0x52, 0x53, 0x9a, 0x7c, 0x31, 0xac, 0xd4, 0xb9, 0xe6, 0x4b, 0x9b, + 0x4f, 0xf0, 0x4e, 0xfb, 0x1f, 0x9f, 0xdf, 0x28, 0x1f, 0x78, 0xcc, 0xea, 0xf7, 0xdd, 0x8e, 0xc0, + 0x56, 0x25, 0xfa, 0xff, 0x41, 0xca, 0xee, 0x8a, 0xd2, 0x67, 0x2a, 0x2e, 0xc7, 0x20, 0x77, 0x00, + 0x44, 0xfc, 0xd9, 0xb2, 0x02, 0xab, 0x9a, 0x3e, 0x0f, 0x5f, 0x43, 0x34, 0x77, 0x05, 0x8b, 0x42, + 0x1e, 0x92, 0xc5, 0xbb, 0x90, 0x3b, 0xc6, 0x02, 0xec, 0x2b, 0x0b, 0x52, 0xe1, 0x9b, 0x37, 0x01, + 0xe4, 0x6b, 0x04, 0xcf, 0xe3, 0x4b, 0xb1, 0xae, 0xa4, 0xa4, 0x2e, 0x65, 0xbe, 0x0e, 0x85, 0x1d, + 0xdb, 0x39, 0x69, 0xf5, 0xed, 0x0e, 0x6f, 0x9a, 0x32, 0x7d, 0xdb, 0x39, 0x51, 0x67, 0x5d, 0x9b, + 0x3c, 0x8b, 0x9f, 0x51, 0xe7, 0x1b, 0xa8, 0xc0, 0x34, 0x7f, 0x6a, 0x00, 0xe1, 0x40, 0xd5, 0x9e, + 0x44, 0x99, 0x5f, 0xb8, 0x82, 0xa1, 0xbb, 0x42, 0x15, 0x72, 0x3d, 0xcf, 0x1d, 0x0d, 0x37, 0x95, + 0x8b, 0xa8, 0x29, 0xc7, 0xef, 0xe3, 0x63, 0x84, 0xa8, 0xef, 0xc4, 0xe4, 0x2b, 0xbb, 0xce, 0xcf, + 0x0d, 0xb8, 0xaa, 0x31, 0xd1, 0x1a, 0x0d, 0x06, 0x96, 0x77, 0xf6, 0xbf, 0xe1, 0xe5, 0xf7, 0x06, + 0x5c, 0x89, 0x09, 0x24, 0xf2, 0x61, 0xe6, 0x07, 0xf6, 0x80, 0xc7, 0x47, 0xe4, 0x24, 0x4f, 0x23, + 0x40, 0xbc, 0xcc, 0x17, 0x95, 0xa1, 0x56, 0xe6, 0x3f, 0x0b, 0x73, 0x68, 0xce, 0xad, 0x10, 0x45, + 0xb0, 0x36, 0x06, 0x25, 0xf5, 0xa8, 0x89, 0x4c, 0xa3, 0x06, 0x17, 0x63, 0x45, 0xfe, 0x44, 0x0b, + 0xf9, 0x3d, 0x28, 0x51, 0xeb, 0xa3, 0x37, 0x6c, 0x3f, 0x70, 0x7b, 0x9e, 0x35, 0xe0, 0x46, 0x72, + 0x3c, 0xea, 0x9c, 0x30, 0xd1, 0x69, 0xa4, 0xa9, 0x9c, 0xf1, 0xbb, 0x77, 0x34, 0xce, 0xc4, 0xc4, + 0x7c, 0x13, 0xf2, 0xaa, 0x4c, 0x4e, 0xe8, 0x7c, 0x5e, 0x88, 0x77, 0x3e, 0x4b, 0xf1, 0x6e, 0xeb, + 0xed, 0x1d, 0xde, 0xde, 0xd8, 0x1d, 0x15, 0x8d, 0x7e, 0x65, 0x40, 0x51, 0x63, 0x91, 0x6c, 0xc2, + 0x42, 0xdf, 0x0a, 0x98, 0xd3, 0x39, 0x3b, 0x7a, 0xa8, 0xd8, 0x93, 0x56, 0x19, 0xf5, 0x50, 0x3a, + 0xef, 0xb4, 0x22, 0xf1, 0xa3, 0xdb, 0xfc, 0x3f, 0x64, 0x7d, 0xe6, 0xd9, 0xd2, 0xbd, 0xf5, 0x08, + 0x16, 0x56, 0xf7, 0x12, 0x81, 0x5f, 0x5c, 0xc4, 0x0b, 0x29, 0x58, 0x39, 0x33, 0xff, 0x16, 0xb7, + 0x6e, 0x69, 0x58, 0x93, 0x4d, 0xd9, 0x05, 0xda, 0x9a, 0x4d, 0xd4, 0x56, 0xc4, 0x5f, 0xea, 0x22, + 0xfe, 0x2a, 0x90, 0x1a, 0xde, 0xbd, 0x2b, 0x5b, 0x1a, 0x3e, 0x14, 0x90, 0x3b, 0x68, 0x78, 0x08, + 0xb9, 0x23, 0x20, 0xeb, 0xb2, 0x8e, 0xe7, 0x43, 0x84, 0xdc, 0x59, 0x97, 0x05, 0x3b, 0x1f, 0x9a, + 0xef, 0x42, 0x2d, 0xc9, 0x4f, 0xa4, 0x89, 0xde, 0x85, 0x82, 0x8f, 0x20, 0x9b, 0x4d, 0x86, 0x80, + 0x84, 0x7d, 0x11, 0xb6, 0xf9, 0x6b, 0x03, 0xca, 0x31, 0xc5, 0xc6, 0x32, 0x51, 0x46, 0x66, 0xa2, + 0x12, 0x18, 0x0e, 0x0a, 0x23, 0x45, 0x0d, 0x87, 0xcf, 0x1e, 0xa0, 0xbc, 0x0d, 0x6a, 0x3c, 0xe0, + 0x33, 0x5f, 0xbe, 0xba, 0x1a, 0x3e, 0x9f, 0x1d, 0xe3, 0xe5, 0xf2, 0xd4, 0x38, 0xe6, 0xb3, 0xae, + 0xbc, 0x98, 0xd1, 0xc5, 0x1e, 0x52, 0x3c, 0xf0, 0xe6, 0x90, 0xb6, 0x7a, 0xbd, 0x25, 0x90, 0x3e, + 0xb1, 0x9d, 0x2e, 0x56, 0x47, 0x19, 0x8a, 0x63, 0x93, 0x89, 0x07, 0x49, 0xc9, 0x38, 0x0f, 0xb3, + 0xbc, 0xf4, 0xf1, 0x98, 0x3f, 0xea, 0x07, 0xed, 0x28, 0x51, 0x6a, 0x10, 0x5e, 0x6a, 0x88, 0x99, + 0x34, 0x9b, 0x5a, 0xa2, 0x0f, 0x21, 0x06, 0x95, 0x98, 0x3c, 0x0a, 0x2e, 0x4c, 0xac, 0x72, 0x33, + 0xe9, 0x5b, 0xc7, 0xac, 0xaf, 0xd5, 0x0a, 0x11, 0x80, 0xf3, 0x81, 0x93, 0x43, 0x2d, 0x37, 0x6b, + 0x10, 0xb2, 0x06, 0xb3, 0x81, 0x32, 0x8d, 0x1b, 0xd3, 0x79, 0x38, 0x70, 0x6d, 0x27, 0xa0, 0xb3, + 0x81, 0xcf, 0x7d, 0x68, 0x29, 0x79, 0x19, 0x95, 0x61, 0x4b, 0x26, 0xca, 0x14, 0xc7, 0xdc, 0x3a, + 0x4e, 0xad, 0x3e, 0x1e, 0x6c, 0x50, 0x3e, 0xe4, 0x5d, 0x21, 0x7b, 0xc4, 0x06, 0xc3, 0xbe, 0xe5, + 0xb5, 0xe5, 0x0b, 0x52, 0x0a, 0x3f, 0x2a, 0x8c, 0x83, 0xc9, 0x73, 0x50, 0x51, 0x20, 0xf5, 0xa2, + 0x2c, 0x8d, 0x73, 0x02, 0x6e, 0xb6, 0xe0, 0x0a, 0x3e, 0x0e, 0x6f, 0x3b, 0x7e, 0x60, 0x39, 0xc1, + 0xf9, 0x51, 0x39, 0x8c, 0xb2, 0x32, 0xd2, 0xc4, 0xa2, 0xac, 0xf0, 0x4d, 0x8c, 0xb2, 0x8f, 0x60, + 0x31, 0x4e, 0x54, 0x9a, 0x70, 0x3d, 0xf4, 0x29, 0x61, 0xbf, 0x51, 0xd8, 0x91, 0x98, 0x2d, 0x5c, + 0x0d, 0x1d, 0xeb, 0xf1, 0x9f, 0xdd, 0x7e, 0x62, 0x40, 0x39, 0x46, 0x8b, 0xdc, 0x85, 0x2c, 0xaa, + 0x6d, 0xd2, 0x67, 0x26, 0xdf, 0x13, 0xe4, 0x6b, 0xbe, 0xdc, 0x10, 0x2f, 0xcd, 0x0c, 0x19, 0x0c, + 0xc9, 0x0d, 0x28, 0x0e, 0x3d, 0x77, 0x70, 0x24, 0xa9, 0x8a, 0xb7, 0x37, 0xe0, 0xa0, 0x1d, 0x84, + 0x98, 0x7f, 0x48, 0xc1, 0x02, 0x5e, 0x9f, 0x5a, 0x4e, 0x8f, 0x5d, 0x8a, 0x44, 0xb1, 0x4b, 0x08, + 0xd8, 0x50, 0xaa, 0x11, 0xc7, 0xf1, 0xef, 0x40, 0xb9, 0xf1, 0xef, 0x40, 0x5a, 0x67, 0x95, 0x3f, + 0xa7, 0xb3, 0x2a, 0x5c, 0xd8, 0x59, 0x41, 0x52, 0x67, 0xa5, 0xf5, 0x33, 0xc5, 0x78, 0x3f, 0xa3, + 0xf7, 0x5c, 0xa5, 0xb1, 0x9e, 0x4b, 0xf5, 0x3a, 0xe5, 0xa9, 0xbd, 0xce, 0xdc, 0x57, 0xea, 0x75, + 0xe6, 0x1f, 0xb7, 0xd7, 0xc1, 0xfc, 0x2e, 0x4d, 0xdf, 0xaf, 0x56, 0xc4, 0x9d, 0x43, 0x80, 0xe9, + 0x03, 0xd1, 0x15, 0x26, 0xad, 0xf5, 0xf9, 0x31, 0x6b, 0xbd, 0x12, 0x25, 0x49, 0x7b, 0xc0, 0xbe, + 0xb6, 0xa9, 0xfe, 0x18, 0xf2, 0x4d, 0xc9, 0xc1, 0xe5, 0x1b, 0xe9, 0xd3, 0x50, 0xe2, 0x61, 0xc4, + 0x0f, 0xac, 0xc1, 0xf0, 0x68, 0x20, 0xac, 0x34, 0x45, 0x8b, 0x21, 0x6c, 0xd7, 0x37, 0x37, 0x20, + 0xdb, 0xb2, 0x06, 0xc3, 0xfe, 0x24, 0xf2, 0xec, 0x04, 0x72, 0x74, 0x8a, 0xa1, 0x9d, 0x62, 0x7e, + 0x6a, 0x00, 0x44, 0xb2, 0xf8, 0x3a, 0xb7, 0x58, 0x83, 0x9c, 0x8f, 0xcc, 0xa8, 0x72, 0x60, 0x3e, + 0x12, 0x1f, 0xc2, 0x25, 0xbe, 0xc2, 0xba, 0xd0, 0x0b, 0xc9, 0x1d, 0x5d, 0xe3, 0xe9, 0xb1, 0x14, + 0xae, 0x04, 0x2f, 0xa9, 0x46, 0x98, 0xcf, 0x7d, 0x00, 0xf3, 0x63, 0xcd, 0x0a, 0x29, 0x41, 0x7e, + 0x6f, 0xff, 0xa8, 0x49, 0xe9, 0x3e, 0xad, 0xcc, 0x90, 0x2b, 0x30, 0xbf, 0xbb, 0xf1, 0xde, 0xd1, + 0xce, 0xf6, 0x61, 0xf3, 0xa8, 0x4d, 0x37, 0xee, 0x35, 0x5b, 0x15, 0x83, 0x03, 0x71, 0x7c, 0xd4, + 0xde, 0xdf, 0x3f, 0xda, 0xd9, 0xa0, 0xf7, 0x9b, 0x95, 0x59, 0xb2, 0x00, 0xe5, 0x77, 0xf6, 0xde, + 0xda, 0xdb, 0x7f, 0x77, 0x4f, 0x6e, 0x4e, 0x35, 0x7e, 0x61, 0x40, 0x96, 0x93, 0x67, 0x1e, 0xf9, + 0x01, 0x14, 0xc2, 0x96, 0x87, 0x5c, 0x8d, 0x75, 0x4a, 0x7a, 0x1b, 0x54, 0x7b, 0x22, 0xb6, 0xa4, + 0x8c, 0xd3, 0x9c, 0x21, 0x1b, 0x50, 0x0c, 0x91, 0x0f, 0x1b, 0xff, 0x0d, 0x89, 0xc6, 0xbf, 0x0c, + 0xa8, 0x48, 0xbb, 0xbc, 0xcf, 0x1c, 0xe6, 0x59, 0x81, 0x1b, 0x32, 0x86, 0xfd, 0xca, 0x18, 0x55, + 0xbd, 0xf9, 0x99, 0xce, 0xd8, 0x36, 0xc0, 0x7d, 0x16, 0xa8, 0x5a, 0xf1, 0x5a, 0x72, 0x72, 0x14, + 0x34, 0xae, 0x4f, 0xc9, 0x9c, 0x8a, 0xd4, 0x7d, 0x80, 0xc8, 0x31, 0x49, 0x94, 0xeb, 0x27, 0xc2, + 0x6b, 0xed, 0x5a, 0xe2, 0x5a, 0x78, 0xd3, 0xdf, 0xa5, 0x21, 0xc7, 0x17, 0x6c, 0xe6, 0x91, 0x37, + 0xa0, 0xfc, 0x43, 0xdb, 0xe9, 0x86, 0x1f, 0x83, 0xc9, 0xd5, 0xa4, 0x6f, 0xd0, 0x82, 0x6c, 0x6d, + 0xfa, 0xe7, 0x69, 0x54, 0x41, 0x49, 0x7d, 0x5e, 0xea, 0x30, 0x27, 0x20, 0x53, 0xbe, 0x69, 0xd6, + 0x9e, 0x9c, 0x80, 0x87, 0x24, 0x9a, 0x50, 0xd4, 0xbe, 0x97, 0xea, 0xd2, 0x9a, 0xf8, 0x8a, 0x7a, + 0x1e, 0x99, 0xfb, 0x00, 0xd1, 0x6b, 0x0a, 0x39, 0xe7, 0x5d, 0xb5, 0x76, 0x2d, 0x71, 0x2d, 0x24, + 0xf4, 0x96, 0xba, 0x92, 0x78, 0x96, 0x39, 0x97, 0xd4, 0x53, 0x89, 0xcf, 0x3c, 0x1a, 0xb1, 0x43, + 0x98, 0x1f, 0x7b, 0xc5, 0x20, 0x17, 0x3d, 0x0e, 0xd6, 0x56, 0xa6, 0x23, 0x84, 0x74, 0xdf, 0xd7, + 0xde, 0x8e, 0xd4, 0xeb, 0xc8, 0xc5, 0x94, 0xcd, 0x69, 0x08, 0x3a, 0xcf, 0x8d, 0xbf, 0xa6, 0xa1, + 0xd2, 0x0a, 0x3c, 0x66, 0x0d, 0x6c, 0xa7, 0xa7, 0x4c, 0xe6, 0x35, 0xc8, 0xca, 0xc4, 0xf7, 0xb8, + 0x2a, 0x5e, 0x37, 0xb8, 0x3f, 0x5c, 0x8a, 0x6e, 0xd6, 0x0d, 0xb2, 0x7b, 0x89, 0xda, 0x59, 0x37, + 0xc8, 0x7b, 0xdf, 0x8c, 0x7e, 0xd6, 0x0d, 0xf2, 0xc1, 0x37, 0xa7, 0xa1, 0x75, 0x83, 0x1c, 0xc0, + 0x82, 0x8c, 0x15, 0x97, 0x12, 0x1d, 0xd6, 0x0d, 0x72, 0x08, 0x57, 0x74, 0x8a, 0xb2, 0x84, 0x24, + 0xd7, 0xe3, 0xfb, 0xe2, 0x45, 0xb2, 0x26, 0xe1, 0xa4, 0x6a, 0x97, 0xd3, 0x6d, 0xfc, 0xd1, 0x80, + 0x9c, 0x8a, 0x84, 0x47, 0x89, 0xdd, 0xaa, 0x79, 0x5e, 0x0f, 0x27, 0x0f, 0x7a, 0xe6, 0x5c, 0x9c, + 0x4b, 0x8f, 0x96, 0x9b, 0xaf, 0x7f, 0xfc, 0xc5, 0xb2, 0xf1, 0xe9, 0x17, 0xcb, 0xc6, 0x3f, 0xbf, + 0x58, 0x36, 0x7e, 0xf9, 0xe5, 0xf2, 0xcc, 0xa7, 0x5f, 0x2e, 0xcf, 0x7c, 0xf6, 0xe5, 0xf2, 0xcc, + 0xfb, 0x37, 0xf5, 0xff, 0x4a, 0x79, 0xd6, 0x03, 0xcb, 0xb1, 0xc4, 0x9f, 0xad, 0xd6, 0xb4, 0xbf, + 0x5f, 0x1d, 0x67, 0xf1, 0x3f, 0x51, 0x2f, 0xfd, 0x27, 0x00, 0x00, 0xff, 0xff, 0x58, 0x5b, 0x43, + 0x93, 0x94, 0x25, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/pkg/tempopb/tempo.proto b/pkg/tempopb/tempo.proto index 5acd1ad612f..5e0ab101371 100644 --- a/pkg/tempopb/tempo.proto +++ b/pkg/tempopb/tempo.proto @@ -2,6 +2,8 @@ syntax = "proto3"; package tempopb; +option go_package = "github.com/grafana/tempo/pkg/tempopb"; + import "common/v1/common.proto"; import "github.com/gogo/protobuf/gogoproto/gogo.proto"; import "trace/v1/trace.proto"; diff --git a/tempodb/backend/v1/v1.pb.go b/tempodb/backend/v1/v1.pb.go new file mode 100644 index 00000000000..b6ee6b0da3b --- /dev/null +++ b/tempodb/backend/v1/v1.pb.go @@ -0,0 +1,1508 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: tempodb/backend/v1/v1.proto + +package v1 + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + tempopb "github.com/grafana/tempo/pkg/tempopb" + _ "google.golang.org/protobuf/types/known/timestamppb" + io "io" + math "math" + math_bits "math/bits" + time "time" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf +var _ = time.Kitchen + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type BlockMeta struct { + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"format"` + BlockId []byte `protobuf:"bytes,2,opt,name=block_id,json=blockId,proto3" json:"blockID"` + TenantId string `protobuf:"bytes,5,opt,name=tenant_id,json=tenantId,proto3" json:"tenantID"` + StartTime time.Time `protobuf:"bytes,6,opt,name=start_time,json=startTime,proto3,stdtime" json:"startTime"` + EndTime time.Time `protobuf:"bytes,7,opt,name=end_time,json=endTime,proto3,stdtime" json:"endTime"` + TotalObjects int32 `protobuf:"varint,8,opt,name=total_objects,json=totalObjects,proto3" json:"totalObjects"` + Size_ uint64 `protobuf:"varint,9,opt,name=size,proto3" json:"size,omitempty"` + CompactionLevel uint32 `protobuf:"varint,10,opt,name=compaction_level,json=compactionLevel,proto3" json:"compactionLevel"` + Encoding uint32 `protobuf:"varint,11,opt,name=encoding,proto3" json:"encoding,omitempty"` + IndexPageSize uint32 `protobuf:"varint,12,opt,name=index_page_size,json=indexPageSize,proto3" json:"indexPageSize"` + TotalRecords uint32 `protobuf:"varint,13,opt,name=total_records,json=totalRecords,proto3" json:"totalRecords"` + DataEncoding string `protobuf:"bytes,14,opt,name=data_encoding,json=dataEncoding,proto3" json:"dataEncoding"` + BloomShardCount uint32 `protobuf:"varint,15,opt,name=bloom_shard_count,json=bloomShardCount,proto3" json:"bloomShards"` + FooterSize uint32 `protobuf:"varint,16,opt,name=footer_size,json=footerSize,proto3" json:"footerSize"` + DedicatedColumns []*tempopb.DedicatedColumn `protobuf:"bytes,17,rep,name=dedicated_columns,json=dedicatedColumns,proto3" json:"dedicatedColumns,omitempty"` + ReplicationFactor uint32 `protobuf:"varint,18,opt,name=replication_factor,json=replicationFactor,proto3" json:"replicationFactor,omitempty"` +} + +func (m *BlockMeta) Reset() { *m = BlockMeta{} } +func (m *BlockMeta) String() string { return proto.CompactTextString(m) } +func (*BlockMeta) ProtoMessage() {} +func (*BlockMeta) Descriptor() ([]byte, []int) { + return fileDescriptor_6bc10ae735c1a340, []int{0} +} +func (m *BlockMeta) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *BlockMeta) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_BlockMeta.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *BlockMeta) XXX_Merge(src proto.Message) { + xxx_messageInfo_BlockMeta.Merge(m, src) +} +func (m *BlockMeta) XXX_Size() int { + return m.Size() +} +func (m *BlockMeta) XXX_DiscardUnknown() { + xxx_messageInfo_BlockMeta.DiscardUnknown(m) +} + +var xxx_messageInfo_BlockMeta proto.InternalMessageInfo + +func (m *BlockMeta) GetVersion() string { + if m != nil { + return m.Version + } + return "" +} + +func (m *BlockMeta) GetBlockId() []byte { + if m != nil { + return m.BlockId + } + return nil +} + +func (m *BlockMeta) GetTenantId() string { + if m != nil { + return m.TenantId + } + return "" +} + +func (m *BlockMeta) GetStartTime() time.Time { + if m != nil { + return m.StartTime + } + return time.Time{} +} + +func (m *BlockMeta) GetEndTime() time.Time { + if m != nil { + return m.EndTime + } + return time.Time{} +} + +func (m *BlockMeta) GetTotalObjects() int32 { + if m != nil { + return m.TotalObjects + } + return 0 +} + +func (m *BlockMeta) GetSize_() uint64 { + if m != nil { + return m.Size_ + } + return 0 +} + +func (m *BlockMeta) GetCompactionLevel() uint32 { + if m != nil { + return m.CompactionLevel + } + return 0 +} + +func (m *BlockMeta) GetEncoding() uint32 { + if m != nil { + return m.Encoding + } + return 0 +} + +func (m *BlockMeta) GetIndexPageSize() uint32 { + if m != nil { + return m.IndexPageSize + } + return 0 +} + +func (m *BlockMeta) GetTotalRecords() uint32 { + if m != nil { + return m.TotalRecords + } + return 0 +} + +func (m *BlockMeta) GetDataEncoding() string { + if m != nil { + return m.DataEncoding + } + return "" +} + +func (m *BlockMeta) GetBloomShardCount() uint32 { + if m != nil { + return m.BloomShardCount + } + return 0 +} + +func (m *BlockMeta) GetFooterSize() uint32 { + if m != nil { + return m.FooterSize + } + return 0 +} + +func (m *BlockMeta) GetDedicatedColumns() []*tempopb.DedicatedColumn { + if m != nil { + return m.DedicatedColumns + } + return nil +} + +func (m *BlockMeta) GetReplicationFactor() uint32 { + if m != nil { + return m.ReplicationFactor + } + return 0 +} + +type CompactedBlockMeta struct { + BlockMeta `protobuf:"bytes,1,opt,name=block_meta,json=blockMeta,proto3,embedded=block_meta" json:"block_meta"` + CompactedTime time.Time `protobuf:"bytes,2,opt,name=compacted_time,json=compactedTime,proto3,stdtime" json:"compacted_time"` +} + +func (m *CompactedBlockMeta) Reset() { *m = CompactedBlockMeta{} } +func (m *CompactedBlockMeta) String() string { return proto.CompactTextString(m) } +func (*CompactedBlockMeta) ProtoMessage() {} +func (*CompactedBlockMeta) Descriptor() ([]byte, []int) { + return fileDescriptor_6bc10ae735c1a340, []int{1} +} +func (m *CompactedBlockMeta) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CompactedBlockMeta) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CompactedBlockMeta.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CompactedBlockMeta) XXX_Merge(src proto.Message) { + xxx_messageInfo_CompactedBlockMeta.Merge(m, src) +} +func (m *CompactedBlockMeta) XXX_Size() int { + return m.Size() +} +func (m *CompactedBlockMeta) XXX_DiscardUnknown() { + xxx_messageInfo_CompactedBlockMeta.DiscardUnknown(m) +} + +var xxx_messageInfo_CompactedBlockMeta proto.InternalMessageInfo + +func (m *CompactedBlockMeta) GetCompactedTime() time.Time { + if m != nil { + return m.CompactedTime + } + return time.Time{} +} + +type TenantIndex struct { + CreatedAt time.Time `protobuf:"bytes,1,opt,name=created_at,json=createdAt,proto3,stdtime" json:"created_at"` + Meta []*BlockMeta `protobuf:"bytes,2,rep,name=meta,proto3" json:"meta,omitempty"` + CompactedMeta []*CompactedBlockMeta `protobuf:"bytes,3,rep,name=compacted_meta,json=compactedMeta,proto3" json:"compacted_meta,omitempty"` +} + +func (m *TenantIndex) Reset() { *m = TenantIndex{} } +func (m *TenantIndex) String() string { return proto.CompactTextString(m) } +func (*TenantIndex) ProtoMessage() {} +func (*TenantIndex) Descriptor() ([]byte, []int) { + return fileDescriptor_6bc10ae735c1a340, []int{2} +} +func (m *TenantIndex) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TenantIndex) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TenantIndex.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TenantIndex) XXX_Merge(src proto.Message) { + xxx_messageInfo_TenantIndex.Merge(m, src) +} +func (m *TenantIndex) XXX_Size() int { + return m.Size() +} +func (m *TenantIndex) XXX_DiscardUnknown() { + xxx_messageInfo_TenantIndex.DiscardUnknown(m) +} + +var xxx_messageInfo_TenantIndex proto.InternalMessageInfo + +func (m *TenantIndex) GetCreatedAt() time.Time { + if m != nil { + return m.CreatedAt + } + return time.Time{} +} + +func (m *TenantIndex) GetMeta() []*BlockMeta { + if m != nil { + return m.Meta + } + return nil +} + +func (m *TenantIndex) GetCompactedMeta() []*CompactedBlockMeta { + if m != nil { + return m.CompactedMeta + } + return nil +} + +func init() { + proto.RegisterType((*BlockMeta)(nil), "backend.v1.BlockMeta") + proto.RegisterType((*CompactedBlockMeta)(nil), "backend.v1.CompactedBlockMeta") + proto.RegisterType((*TenantIndex)(nil), "backend.v1.TenantIndex") +} + +func init() { proto.RegisterFile("tempodb/backend/v1/v1.proto", fileDescriptor_6bc10ae735c1a340) } + +var fileDescriptor_6bc10ae735c1a340 = []byte{ + // 767 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0x4f, 0x6b, 0xe3, 0x46, + 0x14, 0xb7, 0xb2, 0xd9, 0xd8, 0x1e, 0xd9, 0xb1, 0x3d, 0xcb, 0x52, 0xe1, 0x05, 0xc9, 0x84, 0x52, + 0xbc, 0xb4, 0x95, 0x48, 0x4a, 0x0f, 0xa5, 0x10, 0xa8, 0x9c, 0x14, 0xd2, 0xbf, 0x41, 0xc9, 0xa9, + 0x17, 0x31, 0xd2, 0x8c, 0x15, 0x35, 0x92, 0x46, 0x48, 0x63, 0xd3, 0xe6, 0x53, 0xe4, 0xd6, 0x73, + 0xbf, 0x4b, 0x0f, 0x39, 0xe6, 0xd8, 0x93, 0x5a, 0x92, 0x9b, 0x3e, 0x45, 0x99, 0x27, 0xd9, 0xb2, + 0x93, 0x42, 0xf6, 0xe4, 0x79, 0xbf, 0x3f, 0x4f, 0xf3, 0x9b, 0xf1, 0x1b, 0xf4, 0x4e, 0xb0, 0x38, + 0xe5, 0xd4, 0xb3, 0x3c, 0xe2, 0x5f, 0xb3, 0x84, 0x5a, 0xcb, 0x43, 0x6b, 0x79, 0x68, 0xa6, 0x19, + 0x17, 0x1c, 0xa3, 0x1a, 0x34, 0x97, 0x87, 0xe3, 0x8f, 0xd2, 0xeb, 0xc0, 0x02, 0x71, 0xea, 0x55, + 0xbf, 0x95, 0x68, 0x6c, 0x04, 0x9c, 0x07, 0x11, 0xb3, 0xa0, 0xf2, 0x16, 0x73, 0x4b, 0x84, 0x31, + 0xcb, 0x05, 0x89, 0xd3, 0x5a, 0xf0, 0x79, 0x10, 0x8a, 0xab, 0x85, 0x67, 0xfa, 0x3c, 0xb6, 0x02, + 0x1e, 0xf0, 0x46, 0x29, 0x2b, 0x28, 0x60, 0x55, 0xc9, 0x0f, 0xfe, 0x68, 0xa3, 0xae, 0x1d, 0x71, + 0xff, 0xfa, 0x47, 0x26, 0x08, 0xfe, 0x18, 0xb5, 0x97, 0x2c, 0xcb, 0x43, 0x9e, 0x68, 0xca, 0x44, + 0x99, 0x76, 0x6d, 0x54, 0x16, 0xc6, 0xde, 0x9c, 0x67, 0x31, 0x11, 0xce, 0x8a, 0xc2, 0x9f, 0xa0, + 0x8e, 0x27, 0x2d, 0x6e, 0x48, 0xb5, 0x9d, 0x89, 0x32, 0xed, 0xd9, 0x6a, 0x59, 0x18, 0x6d, 0xc0, + 0xce, 0x4e, 0x9c, 0x7a, 0x41, 0xf1, 0x7b, 0xd4, 0x15, 0x2c, 0x21, 0x89, 0x90, 0xc2, 0xd7, 0xd0, + 0xaf, 0x57, 0x16, 0x46, 0xa7, 0x02, 0xcf, 0x4e, 0x9c, 0xd5, 0x8a, 0xe2, 0x73, 0x84, 0x72, 0x41, + 0x32, 0xe1, 0xca, 0x38, 0xda, 0xde, 0x44, 0x99, 0xaa, 0x47, 0x63, 0xb3, 0xca, 0x6a, 0xae, 0x12, + 0x98, 0x97, 0xab, 0xac, 0xf6, 0xdb, 0xbb, 0xc2, 0x68, 0x95, 0x85, 0xd1, 0x05, 0x97, 0xc4, 0x6f, + 0xff, 0x31, 0x14, 0xa7, 0x29, 0xf1, 0x77, 0xa8, 0xc3, 0x12, 0x5a, 0xf5, 0x6b, 0xbf, 0xd8, 0xef, + 0x4d, 0xdd, 0xaf, 0xcd, 0x12, 0xba, 0xee, 0xb6, 0x2a, 0xf0, 0x97, 0xa8, 0x2f, 0xb8, 0x20, 0x91, + 0xcb, 0xbd, 0x5f, 0x99, 0x2f, 0x72, 0xad, 0x33, 0x51, 0xa6, 0xaf, 0xed, 0x61, 0x59, 0x18, 0x3d, + 0x20, 0x7e, 0xae, 0x70, 0x67, 0xab, 0xc2, 0x18, 0xed, 0xe6, 0xe1, 0x0d, 0xd3, 0xba, 0x13, 0x65, + 0xba, 0xeb, 0xc0, 0x1a, 0x1f, 0xa3, 0xa1, 0xcf, 0xe3, 0x94, 0xf8, 0x22, 0xe4, 0x89, 0x1b, 0xb1, + 0x25, 0x8b, 0x34, 0x34, 0x51, 0xa6, 0x7d, 0xfb, 0x4d, 0x59, 0x18, 0x83, 0x86, 0xfb, 0x41, 0x52, + 0xce, 0x53, 0x00, 0x8f, 0x65, 0x2c, 0x9f, 0xd3, 0x30, 0x09, 0x34, 0x55, 0xfa, 0x9c, 0x75, 0x8d, + 0xbf, 0x42, 0x83, 0x30, 0xa1, 0xec, 0x37, 0x37, 0x25, 0x01, 0x73, 0xe1, 0xd3, 0x3d, 0x68, 0x3d, + 0x2a, 0x0b, 0xa3, 0x0f, 0xd4, 0x39, 0x09, 0xd8, 0x45, 0x78, 0xc3, 0x9c, 0xed, 0xb2, 0x49, 0x98, + 0x31, 0x9f, 0x67, 0x34, 0xd7, 0xfa, 0x60, 0x6c, 0x12, 0x3a, 0x15, 0xee, 0x6c, 0x55, 0xd2, 0x46, + 0x89, 0x20, 0xee, 0x7a, 0x4b, 0xfb, 0x70, 0xcb, 0x60, 0x93, 0xc4, 0x69, 0x8d, 0x3b, 0x5b, 0x15, + 0xfe, 0x1a, 0x8d, 0xbc, 0x88, 0xf3, 0xd8, 0xcd, 0xaf, 0x48, 0x46, 0x5d, 0x9f, 0x2f, 0x12, 0xa1, + 0x0d, 0xe0, 0x8b, 0x83, 0xb2, 0x30, 0x54, 0x20, 0x2f, 0x24, 0x97, 0x3b, 0x83, 0xa6, 0x98, 0x49, + 0x1d, 0xb6, 0x90, 0x3a, 0xe7, 0x5c, 0xb0, 0xac, 0x4a, 0x38, 0x04, 0xdb, 0x7e, 0x59, 0x18, 0xa8, + 0x82, 0x21, 0xde, 0xc6, 0x1a, 0x33, 0x34, 0xa2, 0x8c, 0x86, 0x3e, 0x11, 0x4c, 0x7e, 0x2b, 0x5a, + 0xc4, 0x49, 0xae, 0x8d, 0x26, 0xaf, 0xa6, 0xea, 0x91, 0x66, 0xd6, 0x33, 0x66, 0x9e, 0xac, 0x14, + 0x33, 0x10, 0xd8, 0x7a, 0x59, 0x18, 0x63, 0xba, 0x0d, 0xe6, 0x9f, 0xf1, 0x38, 0x94, 0x06, 0xf1, + 0xbb, 0x33, 0x7c, 0xca, 0xe1, 0x9f, 0x10, 0xce, 0x58, 0x1a, 0x49, 0x50, 0x5e, 0xed, 0x9c, 0xf8, + 0x82, 0x67, 0x1a, 0x86, 0xed, 0x19, 0x65, 0x61, 0xbc, 0xdb, 0x60, 0xbf, 0x05, 0x72, 0xa3, 0xdd, + 0xe8, 0x19, 0x79, 0xf0, 0xa7, 0x82, 0xf0, 0xac, 0xba, 0x7d, 0x46, 0x9b, 0x11, 0x3d, 0x46, 0xa8, + 0x1a, 0xbe, 0x98, 0x09, 0x02, 0x53, 0xaa, 0x1e, 0xbd, 0x35, 0x9b, 0xa7, 0xc3, 0x5c, 0x4b, 0xed, + 0x8e, 0xfc, 0x53, 0xdf, 0x17, 0x72, 0x2e, 0xbc, 0xb5, 0xff, 0x7b, 0xb4, 0xef, 0xaf, 0xba, 0x56, + 0xd3, 0xb1, 0xf3, 0xe2, 0x74, 0x40, 0x23, 0x18, 0x89, 0xfe, 0xda, 0x2b, 0xd9, 0x83, 0xbf, 0x14, + 0xa4, 0x5e, 0x56, 0x33, 0x2c, 0xff, 0x4e, 0x78, 0x86, 0x90, 0x9f, 0x31, 0x38, 0x68, 0x22, 0xea, + 0xcd, 0x7d, 0x58, 0xe3, 0x6e, 0xed, 0xfb, 0x46, 0xe0, 0xf7, 0x68, 0x17, 0xb2, 0xed, 0xc0, 0x15, + 0xfd, 0x7f, 0x36, 0x07, 0x24, 0xf8, 0x74, 0x33, 0x0c, 0x98, 0x5e, 0x81, 0x49, 0xdf, 0x34, 0x3d, + 0x3f, 0xc4, 0x8d, 0x18, 0x70, 0x50, 0xa7, 0x77, 0x0f, 0xba, 0x72, 0xff, 0xa0, 0x2b, 0xff, 0x3e, + 0xe8, 0xca, 0xed, 0xa3, 0xde, 0xba, 0x7f, 0xd4, 0x5b, 0x7f, 0x3f, 0xea, 0xad, 0x5f, 0x3e, 0xdd, + 0x7c, 0x4d, 0x33, 0x32, 0x27, 0x09, 0xa9, 0x9e, 0x63, 0xeb, 0xf9, 0x4b, 0xee, 0xed, 0x41, 0xc2, + 0x2f, 0xfe, 0x0b, 0x00, 0x00, 0xff, 0xff, 0x68, 0x4a, 0xe1, 0x10, 0xe6, 0x05, 0x00, 0x00, +} + +func (m *BlockMeta) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *BlockMeta) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *BlockMeta) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.ReplicationFactor != 0 { + i = encodeVarintV1(dAtA, i, uint64(m.ReplicationFactor)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x90 + } + if len(m.DedicatedColumns) > 0 { + for iNdEx := len(m.DedicatedColumns) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.DedicatedColumns[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintV1(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x8a + } + } + if m.FooterSize != 0 { + i = encodeVarintV1(dAtA, i, uint64(m.FooterSize)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x80 + } + if m.BloomShardCount != 0 { + i = encodeVarintV1(dAtA, i, uint64(m.BloomShardCount)) + i-- + dAtA[i] = 0x78 + } + if len(m.DataEncoding) > 0 { + i -= len(m.DataEncoding) + copy(dAtA[i:], m.DataEncoding) + i = encodeVarintV1(dAtA, i, uint64(len(m.DataEncoding))) + i-- + dAtA[i] = 0x72 + } + if m.TotalRecords != 0 { + i = encodeVarintV1(dAtA, i, uint64(m.TotalRecords)) + i-- + dAtA[i] = 0x68 + } + if m.IndexPageSize != 0 { + i = encodeVarintV1(dAtA, i, uint64(m.IndexPageSize)) + i-- + dAtA[i] = 0x60 + } + if m.Encoding != 0 { + i = encodeVarintV1(dAtA, i, uint64(m.Encoding)) + i-- + dAtA[i] = 0x58 + } + if m.CompactionLevel != 0 { + i = encodeVarintV1(dAtA, i, uint64(m.CompactionLevel)) + i-- + dAtA[i] = 0x50 + } + if m.Size_ != 0 { + i = encodeVarintV1(dAtA, i, uint64(m.Size_)) + i-- + dAtA[i] = 0x48 + } + if m.TotalObjects != 0 { + i = encodeVarintV1(dAtA, i, uint64(m.TotalObjects)) + i-- + dAtA[i] = 0x40 + } + n1, err1 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.EndTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.EndTime):]) + if err1 != nil { + return 0, err1 + } + i -= n1 + i = encodeVarintV1(dAtA, i, uint64(n1)) + i-- + dAtA[i] = 0x3a + n2, err2 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.StartTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.StartTime):]) + if err2 != nil { + return 0, err2 + } + i -= n2 + i = encodeVarintV1(dAtA, i, uint64(n2)) + i-- + dAtA[i] = 0x32 + if len(m.TenantId) > 0 { + i -= len(m.TenantId) + copy(dAtA[i:], m.TenantId) + i = encodeVarintV1(dAtA, i, uint64(len(m.TenantId))) + i-- + dAtA[i] = 0x2a + } + if len(m.BlockId) > 0 { + i -= len(m.BlockId) + copy(dAtA[i:], m.BlockId) + i = encodeVarintV1(dAtA, i, uint64(len(m.BlockId))) + i-- + dAtA[i] = 0x12 + } + if len(m.Version) > 0 { + i -= len(m.Version) + copy(dAtA[i:], m.Version) + i = encodeVarintV1(dAtA, i, uint64(len(m.Version))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *CompactedBlockMeta) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CompactedBlockMeta) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CompactedBlockMeta) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + n3, err3 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CompactedTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.CompactedTime):]) + if err3 != nil { + return 0, err3 + } + i -= n3 + i = encodeVarintV1(dAtA, i, uint64(n3)) + i-- + dAtA[i] = 0x12 + { + size, err := m.BlockMeta.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintV1(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *TenantIndex) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TenantIndex) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TenantIndex) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.CompactedMeta) > 0 { + for iNdEx := len(m.CompactedMeta) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.CompactedMeta[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintV1(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.Meta) > 0 { + for iNdEx := len(m.Meta) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Meta[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintV1(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + n5, err5 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt):]) + if err5 != nil { + return 0, err5 + } + i -= n5 + i = encodeVarintV1(dAtA, i, uint64(n5)) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintV1(dAtA []byte, offset int, v uint64) int { + offset -= sovV1(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *BlockMeta) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Version) + if l > 0 { + n += 1 + l + sovV1(uint64(l)) + } + l = len(m.BlockId) + if l > 0 { + n += 1 + l + sovV1(uint64(l)) + } + l = len(m.TenantId) + if l > 0 { + n += 1 + l + sovV1(uint64(l)) + } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.StartTime) + n += 1 + l + sovV1(uint64(l)) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.EndTime) + n += 1 + l + sovV1(uint64(l)) + if m.TotalObjects != 0 { + n += 1 + sovV1(uint64(m.TotalObjects)) + } + if m.Size_ != 0 { + n += 1 + sovV1(uint64(m.Size_)) + } + if m.CompactionLevel != 0 { + n += 1 + sovV1(uint64(m.CompactionLevel)) + } + if m.Encoding != 0 { + n += 1 + sovV1(uint64(m.Encoding)) + } + if m.IndexPageSize != 0 { + n += 1 + sovV1(uint64(m.IndexPageSize)) + } + if m.TotalRecords != 0 { + n += 1 + sovV1(uint64(m.TotalRecords)) + } + l = len(m.DataEncoding) + if l > 0 { + n += 1 + l + sovV1(uint64(l)) + } + if m.BloomShardCount != 0 { + n += 1 + sovV1(uint64(m.BloomShardCount)) + } + if m.FooterSize != 0 { + n += 2 + sovV1(uint64(m.FooterSize)) + } + if len(m.DedicatedColumns) > 0 { + for _, e := range m.DedicatedColumns { + l = e.Size() + n += 2 + l + sovV1(uint64(l)) + } + } + if m.ReplicationFactor != 0 { + n += 2 + sovV1(uint64(m.ReplicationFactor)) + } + return n +} + +func (m *CompactedBlockMeta) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.BlockMeta.Size() + n += 1 + l + sovV1(uint64(l)) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CompactedTime) + n += 1 + l + sovV1(uint64(l)) + return n +} + +func (m *TenantIndex) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt) + n += 1 + l + sovV1(uint64(l)) + if len(m.Meta) > 0 { + for _, e := range m.Meta { + l = e.Size() + n += 1 + l + sovV1(uint64(l)) + } + } + if len(m.CompactedMeta) > 0 { + for _, e := range m.CompactedMeta { + l = e.Size() + n += 1 + l + sovV1(uint64(l)) + } + } + return n +} + +func sovV1(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozV1(x uint64) (n int) { + return sovV1(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *BlockMeta) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: BlockMeta: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: BlockMeta: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthV1 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthV1 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Version = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockId", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthV1 + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthV1 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BlockId = append(m.BlockId[:0], dAtA[iNdEx:postIndex]...) + if m.BlockId == nil { + m.BlockId = []byte{} + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TenantId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthV1 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthV1 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TenantId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StartTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthV1 + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthV1 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.StartTime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EndTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthV1 + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthV1 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.EndTime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalObjects", wireType) + } + m.TotalObjects = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalObjects |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Size_", wireType) + } + m.Size_ = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Size_ |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CompactionLevel", wireType) + } + m.CompactionLevel = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CompactionLevel |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Encoding", wireType) + } + m.Encoding = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Encoding |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 12: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IndexPageSize", wireType) + } + m.IndexPageSize = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.IndexPageSize |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 13: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalRecords", wireType) + } + m.TotalRecords = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalRecords |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 14: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DataEncoding", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthV1 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthV1 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DataEncoding = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 15: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field BloomShardCount", wireType) + } + m.BloomShardCount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.BloomShardCount |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 16: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field FooterSize", wireType) + } + m.FooterSize = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.FooterSize |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 17: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DedicatedColumns", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthV1 + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthV1 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DedicatedColumns = append(m.DedicatedColumns, &tempopb.DedicatedColumn{}) + if err := m.DedicatedColumns[len(m.DedicatedColumns)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 18: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ReplicationFactor", wireType) + } + m.ReplicationFactor = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ReplicationFactor |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipV1(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthV1 + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CompactedBlockMeta) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CompactedBlockMeta: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CompactedBlockMeta: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockMeta", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthV1 + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthV1 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.BlockMeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CompactedTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthV1 + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthV1 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.CompactedTime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipV1(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthV1 + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TenantIndex) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TenantIndex: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TenantIndex: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CreatedAt", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthV1 + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthV1 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Meta", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthV1 + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthV1 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Meta = append(m.Meta, &BlockMeta{}) + if err := m.Meta[len(m.Meta)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CompactedMeta", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthV1 + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthV1 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CompactedMeta = append(m.CompactedMeta, &CompactedBlockMeta{}) + if err := m.CompactedMeta[len(m.CompactedMeta)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipV1(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthV1 + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipV1(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowV1 + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowV1 + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowV1 + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthV1 + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupV1 + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthV1 + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthV1 = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowV1 = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupV1 = fmt.Errorf("proto: unexpected end of group") +) diff --git a/tempodb/backend/v1/v1.proto b/tempodb/backend/v1/v1.proto new file mode 100644 index 00000000000..805af379917 --- /dev/null +++ b/tempodb/backend/v1/v1.proto @@ -0,0 +1,41 @@ +syntax = "proto3"; + +package backend.v1; + +import "pkg/tempopb/tempo.proto"; + +import "google/protobuf/timestamp.proto"; +import "github.com/gogo/protobuf/gogoproto/gogo.proto"; + + +option go_package = "github.com/grafana/tempo/tempodb/backend/v1"; + +message BlockMeta { + string version = 1[(gogoproto.jsontag) = "format"]; + bytes block_id = 2[(gogoproto.jsontag) = "blockID"]; + string tenant_id = 5[(gogoproto.jsontag) = "tenantID"]; + google.protobuf.Timestamp start_time = 6[(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = "startTime"]; + google.protobuf.Timestamp end_time = 7[(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = "endTime"]; + int32 total_objects = 8[(gogoproto.jsontag) = "totalObjects"]; + uint64 size = 9; + uint32 compaction_level = 10[(gogoproto.jsontag) = "compactionLevel"]; + uint32 encoding = 11; + uint32 index_page_size = 12[(gogoproto.jsontag) = "indexPageSize"]; + uint32 total_records = 13[(gogoproto.jsontag) = "totalRecords"]; + string data_encoding = 14[(gogoproto.jsontag) = "dataEncoding"]; + uint32 bloom_shard_count = 15[(gogoproto.jsontag) = "bloomShards"]; + uint32 footer_size = 16[(gogoproto.jsontag) = "footerSize"]; + repeated tempopb.DedicatedColumn dedicated_columns = 17[(gogoproto.jsontag) = "dedicatedColumns,omitempty"]; + uint32 replication_factor = 18[(gogoproto.jsontag) = "replicationFactor,omitempty"]; +} + +message CompactedBlockMeta { + BlockMeta block_meta = 1[(gogoproto.embed) = true, (gogoproto.nullable) = false]; + google.protobuf.Timestamp compacted_time = 2[(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; +} + +message TenantIndex { + google.protobuf.Timestamp created_at = 1[(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; + repeated BlockMeta meta = 2; + repeated CompactedBlockMeta compacted_meta = 3; +} From cfa1e5d03d4b54313e8333e49bbde19e0a72fcfe Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Mon, 9 Sep 2024 21:20:58 +0000 Subject: [PATCH 02/71] Functioning blocklist with new package --- tempodb/blocklist/list.go | 73 ++++-- tempodb/blocklist/list_test.go | 353 ++++++++++++++-------------- tempodb/blocklist/poller.go | 59 +++-- tempodb/blocklist/poller_test.go | 383 +++++++++++++++++-------------- 4 files changed, 467 insertions(+), 401 deletions(-) diff --git a/tempodb/blocklist/list.go b/tempodb/blocklist/list.go index 96088578e79..e45a8b5211c 100644 --- a/tempodb/blocklist/list.go +++ b/tempodb/blocklist/list.go @@ -1,18 +1,19 @@ package blocklist import ( + "bytes" "sync" "github.com/google/uuid" - "github.com/grafana/tempo/tempodb/backend" + backend_v1 "github.com/grafana/tempo/tempodb/backend/v1" ) -// PerTenant is a map of tenant ids to backend.BlockMetas -type PerTenant map[string][]*backend.BlockMeta +// PerTenant is a map of tenant ids to backend_v1.BlockMetas +type PerTenant map[string][]*backend_v1.BlockMeta -// PerTenantCompacted is a map of tenant ids to backend.CompactedBlockMetas -type PerTenantCompacted map[string][]*backend.CompactedBlockMeta +// PerTenantCompacted is a map of tenant ids to backend_v1.CompactedBlockMetas +type PerTenantCompacted map[string][]*backend_v1.CompactedBlockMeta // List controls access to a per tenant blocklist and compacted blocklist type List struct { @@ -52,7 +53,7 @@ func (l *List) Tenants() []string { return tenants } -func (l *List) Metas(tenantID string) []*backend.BlockMeta { +func (l *List) Metas(tenantID string) []*backend_v1.BlockMeta { if tenantID == "" { return nil } @@ -60,12 +61,12 @@ func (l *List) Metas(tenantID string) []*backend.BlockMeta { l.mtx.Lock() defer l.mtx.Unlock() - copiedBlocklist := make([]*backend.BlockMeta, 0, len(l.metas[tenantID])) + copiedBlocklist := make([]*backend_v1.BlockMeta, 0, len(l.metas[tenantID])) copiedBlocklist = append(copiedBlocklist, l.metas[tenantID]...) return copiedBlocklist } -func (l *List) CompactedMetas(tenantID string) []*backend.CompactedBlockMeta { +func (l *List) CompactedMetas(tenantID string) []*backend_v1.CompactedBlockMeta { if tenantID == "" { return nil } @@ -73,7 +74,7 @@ func (l *List) CompactedMetas(tenantID string) []*backend.CompactedBlockMeta { l.mtx.Lock() defer l.mtx.Unlock() - copiedBlocklist := make([]*backend.CompactedBlockMeta, 0, len(l.compactedMetas[tenantID])) + copiedBlocklist := make([]*backend_v1.CompactedBlockMeta, 0, len(l.compactedMetas[tenantID])) copiedBlocklist = append(copiedBlocklist, l.compactedMetas[tenantID]...) return copiedBlocklist @@ -102,7 +103,7 @@ func (l *List) ApplyPollResults(m PerTenant, c PerTenantCompacted) { // Update Adds and removes regular or compacted blocks from the in-memory blocklist. // Changes are temporary and will be preserved only for one poll -func (l *List) Update(tenantID string, add []*backend.BlockMeta, remove []*backend.BlockMeta, compactedAdd []*backend.CompactedBlockMeta, compactedRemove []*backend.CompactedBlockMeta) { +func (l *List) Update(tenantID string, add []*backend_v1.BlockMeta, remove []*backend_v1.BlockMeta, compactedAdd []*backend_v1.CompactedBlockMeta, compactedRemove []*backend_v1.CompactedBlockMeta) { if tenantID == "" { return } @@ -125,32 +126,46 @@ func (l *List) Update(tenantID string, add []*backend.BlockMeta, remove []*backe // updateInternal exists to do the work of applying updates to held PerTenant and PerTenantCompacted maps // it must be called under lock -func (l *List) updateInternal(tenantID string, add []*backend.BlockMeta, remove []*backend.BlockMeta, compactedAdd []*backend.CompactedBlockMeta, compactedRemove []*backend.CompactedBlockMeta) { +func (l *List) updateInternal(tenantID string, add []*backend_v1.BlockMeta, remove []*backend_v1.BlockMeta, compactedAdd []*backend_v1.CompactedBlockMeta, compactedRemove []*backend_v1.CompactedBlockMeta) { // ******** Regular blocks ******** blocklist := l.metas[tenantID] matchedRemovals := make(map[uuid.UUID]struct{}) for _, b := range blocklist { for _, rem := range remove { - if b.BlockID == rem.BlockID { - matchedRemovals[rem.BlockID] = struct{}{} + if bytes.Equal(b.BlockId, rem.BlockId) { + id, err := uuid.ParseBytes(b.BlockId) + if err != nil { + // FIXME + } + matchedRemovals[id] = struct{}{} break } } } existingMetas := make(map[uuid.UUID]struct{}) - newblocklist := make([]*backend.BlockMeta, 0, len(blocklist)-len(matchedRemovals)+len(add)) + newblocklist := make([]*backend_v1.BlockMeta, 0, len(blocklist)-len(matchedRemovals)+len(add)) + // var id uuid.UUID + // var err error // rebuild the blocklist dropping all removals for _, b := range blocklist { - existingMetas[b.BlockID] = struct{}{} - if _, ok := matchedRemovals[b.BlockID]; !ok { + id, err := uuid.ParseBytes(b.BlockId) + if err != nil { + // FIXME: + } + existingMetas[id] = struct{}{} + if _, ok := matchedRemovals[id]; !ok { newblocklist = append(newblocklist, b) } } // add new blocks (only if they don't already exist) for _, b := range add { - if _, ok := existingMetas[b.BlockID]; !ok { + id, err := uuid.ParseBytes(b.BlockId) + if err != nil { + // FIXME: + } + if _, ok := existingMetas[id]; !ok { newblocklist = append(newblocklist, b) } } @@ -163,24 +178,36 @@ func (l *List) updateInternal(tenantID string, add []*backend.BlockMeta, remove compactedRemovals := map[uuid.UUID]struct{}{} for _, c := range compactedBlocklist { for _, rem := range compactedRemove { - if c.BlockID == rem.BlockID { - compactedRemovals[rem.BlockID] = struct{}{} + id, err := uuid.ParseBytes(c.BlockId) + if err != nil { + // FIXME: + } + if bytes.Equal(c.BlockId, rem.BlockId) { + compactedRemovals[id] = struct{}{} break } } } existingMetas = make(map[uuid.UUID]struct{}) - newCompactedBlocklist := make([]*backend.CompactedBlockMeta, 0, len(compactedBlocklist)-len(compactedRemovals)+len(compactedAdd)) + newCompactedBlocklist := make([]*backend_v1.CompactedBlockMeta, 0, len(compactedBlocklist)-len(compactedRemovals)+len(compactedAdd)) // rebuild the blocklist dropping all removals for _, b := range compactedBlocklist { - existingMetas[b.BlockID] = struct{}{} - if _, ok := compactedRemovals[b.BlockID]; !ok { + id, err := uuid.ParseBytes(b.BlockId) + if err != nil { + // FIXME: + } + existingMetas[id] = struct{}{} + if _, ok := compactedRemovals[id]; !ok { newCompactedBlocklist = append(newCompactedBlocklist, b) } } for _, b := range compactedAdd { - if _, ok := existingMetas[b.BlockID]; !ok { + id, err := uuid.ParseBytes(b.BlockId) + if err != nil { + // FIXME: + } + if _, ok := existingMetas[id]; !ok { newCompactedBlocklist = append(newCompactedBlocklist, b) } } diff --git a/tempodb/blocklist/list_test.go b/tempodb/blocklist/list_test.go index efa20ceb6ca..65570654281 100644 --- a/tempodb/blocklist/list_test.go +++ b/tempodb/blocklist/list_test.go @@ -6,8 +6,9 @@ import ( "github.com/google/uuid" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" - "github.com/grafana/tempo/tempodb/backend" + backend_v1 "github.com/grafana/tempo/tempodb/backend/v1" ) const testTenantID = "test" @@ -26,14 +27,14 @@ func TestApplyPollResults(t *testing.T) { { name: "meta only", metas: PerTenant{ - "test": []*backend.BlockMeta{ + "test": []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, - "test2": []*backend.BlockMeta{ + "test2": []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, @@ -42,22 +43,22 @@ func TestApplyPollResults(t *testing.T) { { name: "compacted meta only", compacted: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ + "test": []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, - "test2": []*backend.CompactedBlockMeta{ + "test2": []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, }, @@ -67,34 +68,34 @@ func TestApplyPollResults(t *testing.T) { { name: "all", metas: PerTenant{ - "test": []*backend.BlockMeta{ + "test": []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, - "blerg": []*backend.BlockMeta{ + "blerg": []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, compacted: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ + "test": []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, - "test2": []*backend.CompactedBlockMeta{ + "test2": []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, }, @@ -126,10 +127,10 @@ func TestApplyPollResults(t *testing.T) { func TestUpdate(t *testing.T) { tests := []struct { name string - existing []*backend.BlockMeta - add []*backend.BlockMeta - remove []*backend.BlockMeta - expected []*backend.BlockMeta + existing []*backend_v1.BlockMeta + add []*backend_v1.BlockMeta + remove []*backend_v1.BlockMeta + expected []*backend_v1.BlockMeta }{ { name: "all nil", @@ -141,37 +142,37 @@ func TestUpdate(t *testing.T) { { name: "add to nil", existing: nil, - add: []*backend.BlockMeta{ + add: []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, remove: nil, - expected: []*backend.BlockMeta{ + expected: []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, { name: "add to existing", - existing: []*backend.BlockMeta{ + existing: []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, - add: []*backend.BlockMeta{ + add: []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, remove: nil, - expected: []*backend.BlockMeta{ + expected: []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, }, @@ -179,120 +180,120 @@ func TestUpdate(t *testing.T) { name: "remove from nil", existing: nil, add: nil, - remove: []*backend.BlockMeta{ + remove: []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, expected: nil, }, { name: "remove nil", - existing: []*backend.BlockMeta{ + existing: []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, add: nil, remove: nil, - expected: []*backend.BlockMeta{ + expected: []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, }, { name: "remove existing", - existing: []*backend.BlockMeta{ + existing: []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, add: nil, - remove: []*backend.BlockMeta{ + remove: []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, - expected: []*backend.BlockMeta{ + expected: []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, }, { name: "remove no match", - existing: []*backend.BlockMeta{ + existing: []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, add: nil, - remove: []*backend.BlockMeta{ + remove: []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, - expected: []*backend.BlockMeta{ + expected: []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, { name: "add and remove", - existing: []*backend.BlockMeta{ + existing: []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, - add: []*backend.BlockMeta{ + add: []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000003")), }, }, - remove: []*backend.BlockMeta{ + remove: []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, - expected: []*backend.BlockMeta{ + expected: []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000003")), }, }, }, { name: "add already exists", - existing: []*backend.BlockMeta{ + existing: []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, - add: []*backend.BlockMeta{ + add: []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, remove: nil, - expected: []*backend.BlockMeta{ + expected: []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, }, @@ -308,7 +309,7 @@ func TestUpdate(t *testing.T) { assert.Equal(t, len(tt.expected), len(l.metas[testTenantID])) for i := range tt.expected { - assert.Equal(t, tt.expected[i].BlockID, l.metas[testTenantID][i].BlockID) + assert.Equal(t, tt.expected[i].BlockId, l.metas[testTenantID][i].BlockId) } }) } @@ -317,10 +318,10 @@ func TestUpdate(t *testing.T) { func TestUpdateCompacted(t *testing.T) { tests := []struct { name string - existing []*backend.CompactedBlockMeta - add []*backend.CompactedBlockMeta - remove []*backend.CompactedBlockMeta - expected []*backend.CompactedBlockMeta + existing []*backend_v1.CompactedBlockMeta + add []*backend_v1.CompactedBlockMeta + remove []*backend_v1.CompactedBlockMeta + expected []*backend_v1.CompactedBlockMeta }{ { name: "all nil", @@ -331,121 +332,121 @@ func TestUpdateCompacted(t *testing.T) { { name: "add to nil", existing: nil, - add: []*backend.CompactedBlockMeta{ + add: []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, - expected: []*backend.CompactedBlockMeta{ + expected: []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, }, { name: "add to existing", - existing: []*backend.CompactedBlockMeta{ + existing: []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, - add: []*backend.CompactedBlockMeta{ + add: []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, }, - expected: []*backend.CompactedBlockMeta{ + expected: []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, }, }, { name: "add already exists", - existing: []*backend.CompactedBlockMeta{ + existing: []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, - add: []*backend.CompactedBlockMeta{ + add: []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, }, - expected: []*backend.CompactedBlockMeta{ + expected: []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, }, }, { name: "add and remove", - existing: []*backend.CompactedBlockMeta{ + existing: []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, }, - add: []*backend.CompactedBlockMeta{ + add: []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000003")), }, }, }, - remove: []*backend.CompactedBlockMeta{ + remove: []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, }, - expected: []*backend.CompactedBlockMeta{ + expected: []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000003")), }, }, }, @@ -462,7 +463,7 @@ func TestUpdateCompacted(t *testing.T) { assert.Equal(t, len(tt.expected), len(l.compactedMetas[testTenantID])) for i := range tt.expected { - assert.Equal(t, tt.expected[i].BlockID, l.compactedMetas[testTenantID][i].BlockID) + assert.Equal(t, tt.expected[i].BlockId, l.compactedMetas[testTenantID][i].BlockId) } }) } @@ -481,9 +482,9 @@ func TestUpdatesSaved(t *testing.T) { applyMetas PerTenant applyCompacted PerTenantCompacted updateTenant string - addMetas []*backend.BlockMeta - removeMetas []*backend.BlockMeta - addCompacted []*backend.CompactedBlockMeta + addMetas []*backend_v1.BlockMeta + removeMetas []*backend_v1.BlockMeta + addCompacted []*backend_v1.CompactedBlockMeta expectedTenants []string expectedMetas PerTenant @@ -492,60 +493,60 @@ func TestUpdatesSaved(t *testing.T) { // STEP 1: apply a normal polling data and updates { applyMetas: PerTenant{ - "test": []*backend.BlockMeta{ + "test": []*backend_v1.BlockMeta{ { - BlockID: one, + BlockId: uuidBytes(one), }, }, }, applyCompacted: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ + "test": []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: oneOhOne, + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(oneOhOne), }, }, }, }, updateTenant: "test", - addMetas: []*backend.BlockMeta{ + addMetas: []*backend_v1.BlockMeta{ { - BlockID: one, + BlockId: uuidBytes(one), }, { - BlockID: two, + BlockId: uuidBytes(two), }, }, - removeMetas: []*backend.BlockMeta{ + removeMetas: []*backend_v1.BlockMeta{ { - BlockID: one, + BlockId: uuidBytes(one), }, }, - addCompacted: []*backend.CompactedBlockMeta{ + addCompacted: []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: oneOhTwo, + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(oneOhTwo), }, }, }, expectedTenants: []string{"test"}, expectedMetas: PerTenant{ - "test": []*backend.BlockMeta{ + "test": []*backend_v1.BlockMeta{ { - BlockID: two, + BlockId: uuidBytes(two), }, }, }, expectedCompacted: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ + "test": []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: oneOhOne, + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(oneOhOne), }, }, { - BlockMeta: backend.BlockMeta{ - BlockID: oneOhTwo, + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(oneOhTwo), }, }, }, @@ -554,43 +555,43 @@ func TestUpdatesSaved(t *testing.T) { // STEP 2: same polling apply, no update! but expect the same results { applyMetas: PerTenant{ - "test": []*backend.BlockMeta{ + "test": []*backend_v1.BlockMeta{ { - BlockID: one, + BlockId: uuidBytes(one), }, }, }, applyCompacted: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ + "test": []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: oneOhOne, + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(oneOhOne), }, }, }, }, expectedTenants: []string{"test"}, expectedMetas: PerTenant{ - "test": []*backend.BlockMeta{ + "test": []*backend_v1.BlockMeta{ // Even though we have just appled one, it was removed in the previous step, and we we expect not to find it here. // { - // BlockID: one, + // BlockId: one, // }, { - BlockID: two, + BlockId: uuidBytes(two), }, }, }, expectedCompacted: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ + "test": []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: oneOhOne, + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(oneOhOne), }, }, { - BlockMeta: backend.BlockMeta{ - BlockID: oneOhTwo, + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(oneOhTwo), }, }, }, @@ -599,34 +600,34 @@ func TestUpdatesSaved(t *testing.T) { // STEP 3: same polling apply, no update! but this time the update doesn't impact results { applyMetas: PerTenant{ - "test": []*backend.BlockMeta{ + "test": []*backend_v1.BlockMeta{ { - BlockID: one, + BlockId: uuidBytes(one), }, }, }, applyCompacted: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ + "test": []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: oneOhOne, + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(oneOhOne), }, }, }, }, expectedTenants: []string{"test"}, expectedMetas: PerTenant{ - "test": []*backend.BlockMeta{ + "test": []*backend_v1.BlockMeta{ { - BlockID: one, + BlockId: uuidBytes(one), }, }, }, expectedCompacted: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ + "test": []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: oneOhOne, + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(oneOhOne), }, }, }, @@ -650,6 +651,8 @@ func TestUpdatesSaved(t *testing.T) { sort.Slice(actualTenants, func(i, j int) bool { return actualTenants[i] < actualTenants[j] }) assert.Equal(t, tc.expectedTenants, actualTenants) assert.Equal(t, tc.expectedMetas, actualMetas) + + require.Equal(t, len(tc.expectedCompacted), len(actualCompacted), "expectedCompacted: %+v, actualCompacted: %+v", tc.expectedCompacted, actualCompacted) assert.Equal(t, tc.expectedCompacted, actualCompacted) } } diff --git a/tempodb/blocklist/poller.go b/tempodb/blocklist/poller.go index c54eff800ca..39ae600d063 100644 --- a/tempodb/blocklist/poller.go +++ b/tempodb/blocklist/poller.go @@ -24,6 +24,7 @@ import ( "github.com/grafana/tempo/pkg/boundedwaitgroup" "github.com/grafana/tempo/tempodb/backend" + backend_v1 "github.com/grafana/tempo/tempodb/backend/v1" ) const ( @@ -181,8 +182,8 @@ func (p *Poller) Do(previous *List) (PerTenant, PerTenantCompacted, error) { var ( consecutiveErrorsRemaining = p.cfg.TolerateConsecutiveErrors - newBlockList = make([]*backend.BlockMeta, 0) - newCompactedBlockList = make([]*backend.CompactedBlockMeta, 0) + newBlockList = make([]*backend_v1.BlockMeta, 0) + newCompactedBlockList = make([]*backend_v1.CompactedBlockMeta, 0) err error ) @@ -241,7 +242,7 @@ func (p *Poller) pollTenantAndCreateIndex( ctx context.Context, tenantID string, previous *List, -) ([]*backend.BlockMeta, []*backend.CompactedBlockMeta, error) { +) ([]*backend_v1.BlockMeta, []*backend_v1.CompactedBlockMeta, error) { derivedCtx, span := tracer.Start(ctx, "Poller.pollTenantAndCreateIndex", trace.WithAttributes(attribute.String("tenant", tenantID))) defer span.End() @@ -308,22 +309,22 @@ func (p *Poller) pollTenantBlocks( ctx context.Context, tenantID string, previous *List, -) ([]*backend.BlockMeta, []*backend.CompactedBlockMeta, error) { +) ([]*backend_v1.BlockMeta, []*backend_v1.CompactedBlockMeta, error) { derivedCtx, span := tracer.Start(ctx, "Poller.pollTenantBlocks") defer span.End() currentBlockIDs, currentCompactedBlockIDs, err := p.reader.Blocks(derivedCtx, tenantID) if err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("failed listing tenant blocks: %w", err) } var ( metas = previous.Metas(tenantID) compactedMetas = previous.CompactedMetas(tenantID) - mm = make(map[uuid.UUID]*backend.BlockMeta, len(metas)) - cm = make(map[uuid.UUID]*backend.CompactedBlockMeta, len(compactedMetas)) - newBlockList = make([]*backend.BlockMeta, 0, len(currentBlockIDs)) - newCompactedBlocklist = make([]*backend.CompactedBlockMeta, 0, len(currentCompactedBlockIDs)) + mm = make(map[uuid.UUID]*backend_v1.BlockMeta, len(metas)) + cm = make(map[uuid.UUID]*backend_v1.CompactedBlockMeta, len(compactedMetas)) + newBlockList = make([]*backend_v1.BlockMeta, 0, len(currentBlockIDs)) + newCompactedBlocklist = make([]*backend_v1.CompactedBlockMeta, 0, len(currentCompactedBlockIDs)) unknownBlockIDs = make(map[uuid.UUID]bool, 1000) ) @@ -331,11 +332,19 @@ func (p *Poller) pollTenantBlocks( span.SetAttributes(attribute.Int("compactedMetas", len(compactedMetas))) for _, i := range metas { - mm[i.BlockID] = i + id, err := uuid.ParseBytes(i.BlockId) + if err != nil { + return nil, nil, fmt.Errorf("failed parsing meta UUID bytes: %w", err) + } + mm[id] = i } for _, i := range compactedMetas { - cm[i.BlockID] = i + id, err := uuid.ParseBytes(i.BlockId) + if err != nil { + return nil, nil, fmt.Errorf("failed parsing compacted meta UUID bytes: %w", err) + } + cm[id] = i } // The boolean here to track if we know the block has been compacted @@ -366,7 +375,7 @@ func (p *Poller) pollTenantBlocks( newM, newCm, err := p.pollUnknown(derivedCtx, unknownBlockIDs, tenantID) if err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("failed reading unknown blocks: %w", err) } newBlockList = append(newBlockList, newM...) @@ -387,7 +396,7 @@ func (p *Poller) pollUnknown( ctx context.Context, unknownBlocks map[uuid.UUID]bool, tenantID string, -) ([]*backend.BlockMeta, []*backend.CompactedBlockMeta, error) { +) ([]*backend_v1.BlockMeta, []*backend_v1.CompactedBlockMeta, error) { derivedCtx, span := tracer.Start(ctx, "pollUnknown", trace.WithAttributes( attribute.Int("unknownBlockIDs", len(unknownBlocks)), )) @@ -398,8 +407,8 @@ func (p *Poller) pollUnknown( errs []error mtx sync.Mutex bg = boundedwaitgroup.New(p.cfg.PollConcurrency) - newBlockList = make([]*backend.BlockMeta, 0, len(unknownBlocks)) - newCompactedBlocklist = make([]*backend.CompactedBlockMeta, 0, len(unknownBlocks)) + newBlockList = make([]*backend_v1.BlockMeta, 0, len(unknownBlocks)) + newCompactedBlocklist = make([]*backend_v1.CompactedBlockMeta, 0, len(unknownBlocks)) ) for blockID, compacted := range unknownBlocks { @@ -457,7 +466,7 @@ func (p *Poller) pollBlock( tenantID string, blockID uuid.UUID, compacted bool, -) (*backend.BlockMeta, *backend.CompactedBlockMeta, error) { +) (*backend_v1.BlockMeta, *backend_v1.CompactedBlockMeta, error) { derivedCtx, span := tracer.Start(ctx, "Poller.pollBlock") defer span.End() var err error @@ -465,8 +474,8 @@ func (p *Poller) pollBlock( span.SetAttributes(attribute.String("tenant", tenantID)) span.SetAttributes(attribute.String("block", blockID.String())) - var blockMeta *backend.BlockMeta - var compactedBlockMeta *backend.CompactedBlockMeta + var blockMeta *backend_v1.BlockMeta + var compactedBlockMeta *backend_v1.CompactedBlockMeta if !compacted { blockMeta, err = p.reader.BlockMeta(derivedCtx, blockID, tenantID) @@ -502,7 +511,7 @@ func (p *Poller) tenantIndexBuilder(tenant string) bool { return false } -func (p *Poller) tenantIndexPollError(idx *backend.TenantIndex, err error) error { +func (p *Poller) tenantIndexPollError(idx *backend_v1.TenantIndex, err error) error { if err != nil { return err } @@ -578,8 +587,8 @@ type backendMetaMetrics struct { } func sumTotalBackendMetaMetrics( - blockMeta []*backend.BlockMeta, - compactedBlockMeta []*backend.CompactedBlockMeta, + blockMeta []*backend_v1.BlockMeta, + compactedBlockMeta []*backend_v1.CompactedBlockMeta, ) backendMetaMetrics { var sumTotalObjectsBM int var sumTotalObjectsCBM int @@ -587,13 +596,13 @@ func sumTotalBackendMetaMetrics( var sumTotalBytesCBM uint64 for _, bm := range blockMeta { - sumTotalObjectsBM += bm.TotalObjects - sumTotalBytesBM += bm.Size + sumTotalObjectsBM += int(bm.TotalObjects) + sumTotalBytesBM += bm.Size_ } for _, cbm := range compactedBlockMeta { - sumTotalObjectsCBM += cbm.TotalObjects - sumTotalBytesCBM += cbm.Size + sumTotalObjectsCBM += int(cbm.TotalObjects) + sumTotalBytesCBM += cbm.Size_ } return backendMetaMetrics{ diff --git a/tempodb/blocklist/poller_test.go b/tempodb/blocklist/poller_test.go index 8696f053601..58dd95d88d4 100644 --- a/tempodb/blocklist/poller_test.go +++ b/tempodb/blocklist/poller_test.go @@ -19,6 +19,7 @@ import ( "github.com/stretchr/testify/require" "github.com/grafana/tempo/tempodb/backend" + backend_v1 "github.com/grafana/tempo/tempodb/backend/v1" ) var ( @@ -36,6 +37,12 @@ type mockJobSharder struct { func (m *mockJobSharder) Owns(_ string) bool { return m.owns } func TestTenantIndexBuilder(t *testing.T) { + var ( + one = uuid.MustParse("00000000-0000-0000-0000-000000000001") + two = uuid.MustParse("00000000-0000-0000-0000-000000000002") + three = uuid.MustParse("00000000-0000-0000-0000-000000000003") + ) + tests := []struct { name string list PerTenant @@ -52,9 +59,9 @@ func TestTenantIndexBuilder(t *testing.T) { { name: "err", list: PerTenant{ - "test": []*backend.BlockMeta{ + "test": []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockId: []byte(one.String()), }, }, }, @@ -63,42 +70,42 @@ func TestTenantIndexBuilder(t *testing.T) { { name: "block meta", list: PerTenant{ - "test": []*backend.BlockMeta{ + "test": []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockId: []byte(one.String()), }, }, }, expectedList: PerTenant{ - "test": []*backend.BlockMeta{ + "test": []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockId: []byte(one.String()), }, }, }, expectedCompactedList: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{}, + "test": []*backend_v1.CompactedBlockMeta{}, }, }, { name: "compacted block meta", compactedList: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ + "test": []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: []byte(one.String()), }, }, }, }, expectedList: PerTenant{ - "test": []*backend.BlockMeta{}, + "test": []*backend_v1.BlockMeta{}, }, expectedCompactedList: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ + "test": []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: []byte(one.String()), }, }, }, @@ -107,47 +114,47 @@ func TestTenantIndexBuilder(t *testing.T) { { name: "all", list: PerTenant{ - "test2": []*backend.BlockMeta{ + "test2": []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockId: []byte(three.String()), }, }, - "test": []*backend.BlockMeta{ + "test": []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockId: []byte(two.String()), }, }, }, compactedList: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ + "test": []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: []byte(one.String()), }, }, }, }, expectedList: PerTenant{ - "test2": []*backend.BlockMeta{ + "test2": []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockId: []byte(three.String()), }, }, - "test": []*backend.BlockMeta{ + "test": []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockId: []byte(two.String()), }, }, }, expectedCompactedList: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ + "test": []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: []byte(one.String()), }, }, }, - "test2": []*backend.CompactedBlockMeta{}, + "test2": []*backend_v1.CompactedBlockMeta{}, }, }, } @@ -247,16 +254,16 @@ func TestTenantIndexFallback(t *testing.T) { t.Run(tc.name, func(t *testing.T) { c := &backend.MockCompactor{} r := newMockReader(PerTenant{ - "test": []*backend.BlockMeta{}, + "test": []*backend_v1.BlockMeta{}, }, nil, false) w := &backend.MockWriter{} b := newBlocklist(PerTenant{}, PerTenantCompacted{}) - r.(*backend.MockReader).TenantIndexFn = func(_ context.Context, _ string) (*backend.TenantIndex, error) { + r.(*backend.MockReader).TenantIndexFn = func(_ context.Context, _ string) (*backend_v1.TenantIndex, error) { if tc.errorOnCreateTenantIndex { return nil, errors.New("err") } - return &backend.TenantIndex{ + return &backend_v1.TenantIndex{ CreatedAt: time.Now(). Add(-5 * time.Minute), // always make the tenant index 5 minutes old so the above tests can use that for fallback testing @@ -283,64 +290,66 @@ func TestTenantIndexFallback(t *testing.T) { } func TestPollBlock(t *testing.T) { + one := uuid.MustParse("00000000-0000-0000-0000-000000000001") + tests := []struct { name string list PerTenant compactedList PerTenantCompacted pollTenantID string - pollBlockID uuid.UUID - expectedMeta *backend.BlockMeta - expectedCompactedMeta *backend.CompactedBlockMeta + pollBlockId uuid.UUID + expectedMeta *backend_v1.BlockMeta + expectedCompactedMeta *backend_v1.CompactedBlockMeta expectsError bool }{ { name: "block and tenant don't exist", pollTenantID: "test", - pollBlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + pollBlockId: one, }, { name: "block exists", pollTenantID: "test", - pollBlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + pollBlockId: one, list: PerTenant{ - "test": []*backend.BlockMeta{ + "test": []*backend_v1.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockId: uuidBytes(one), }, }, }, - expectedMeta: &backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + expectedMeta: &backend_v1.BlockMeta{ + BlockId: uuidBytes(one), }, }, { name: "compactedblock exists", pollTenantID: "test", - pollBlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + pollBlockId: uuid.MustParse("00000000-0000-0000-0000-000000000001"), compactedList: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ + "test": []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, }, - expectedCompactedMeta: &backend.CompactedBlockMeta{ - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + expectedCompactedMeta: &backend_v1.CompactedBlockMeta{ + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, { name: "errors", pollTenantID: "test", - pollBlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + pollBlockId: uuid.MustParse("00000000-0000-0000-0000-000000000001"), compactedList: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ + "test": []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockMeta: backend_v1.BlockMeta{ + BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, @@ -361,7 +370,7 @@ func TestPollBlock(t *testing.T) { PollFallback: testPollFallback, TenantIndexBuilders: testBuilders, }, &mockJobSharder{}, r, c, w, log.NewNopLogger()) - actualMeta, actualCompactedMeta, err := poller.pollBlock(context.Background(), tc.pollTenantID, tc.pollBlockID, false) + actualMeta, actualCompactedMeta, err := poller.pollBlock(context.Background(), tc.pollTenantID, tc.pollBlockId, false) assert.Equal(t, tc.expectedMeta, actualMeta) assert.Equal(t, tc.expectedCompactedMeta, actualCompactedMeta) @@ -383,19 +392,19 @@ func TestTenantIndexPollError(t *testing.T) { assert.Error(t, p.tenantIndexPollError(nil, errors.New("blerg"))) // tenant index older than 1 minute is stale, error! - assert.Error(t, p.tenantIndexPollError(&backend.TenantIndex{ + assert.Error(t, p.tenantIndexPollError(&backend_v1.TenantIndex{ CreatedAt: time.Now().Add(-5 * time.Minute), }, nil)) // no error, tenant index is within 1 minute - assert.NoError(t, p.tenantIndexPollError(&backend.TenantIndex{ + assert.NoError(t, p.tenantIndexPollError(&backend_v1.TenantIndex{ CreatedAt: time.Now().Add(-time.Second), }, nil)) p = NewPoller(&PollerConfig{}, nil, nil, nil, nil, log.NewNopLogger()) // no error, index is super old but stale tenant index is 0 - assert.NoError(t, p.tenantIndexPollError(&backend.TenantIndex{ + assert.NoError(t, p.tenantIndexPollError(&backend_v1.TenantIndex{ CreatedAt: time.Now().Add(30 * time.Hour), }, nil)) } @@ -414,7 +423,7 @@ func TestBlockListBackendMetrics(t *testing.T) { { name: "total backend objects calculation is correct", list: PerTenant{ - "test": []*backend.BlockMeta{ + "test": []*backend_v1.BlockMeta{ { TotalObjects: 10, }, @@ -427,24 +436,24 @@ func TestBlockListBackendMetrics(t *testing.T) { }, }, compactedList: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ + "test": []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ + BlockMeta: backend_v1.BlockMeta{ TotalObjects: 7, }, }, { - BlockMeta: backend.BlockMeta{ + BlockMeta: backend_v1.BlockMeta{ TotalObjects: 8, }, }, { - BlockMeta: backend.BlockMeta{ + BlockMeta: backend_v1.BlockMeta{ TotalObjects: 5, }, }, { - BlockMeta: backend.BlockMeta{ + BlockMeta: backend_v1.BlockMeta{ TotalObjects: 15, }, }, @@ -459,38 +468,38 @@ func TestBlockListBackendMetrics(t *testing.T) { { name: "total backend bytes calculation is correct", list: PerTenant{ - "test": []*backend.BlockMeta{ + "test": []*backend_v1.BlockMeta{ { - Size: 250, + Size_: 250, }, { - Size: 500, + Size_: 500, }, { - Size: 250, + Size_: 250, }, }, }, compactedList: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ + "test": []*backend_v1.CompactedBlockMeta{ { - BlockMeta: backend.BlockMeta{ - Size: 300, + BlockMeta: backend_v1.BlockMeta{ + Size_: 300, }, }, { - BlockMeta: backend.BlockMeta{ - Size: 200, + BlockMeta: backend_v1.BlockMeta{ + Size_: 200, }, }, { - BlockMeta: backend.BlockMeta{ - Size: 250, + BlockMeta: backend_v1.BlockMeta{ + Size_: 250, }, }, { - BlockMeta: backend.BlockMeta{ - Size: 500, + BlockMeta: backend_v1.BlockMeta{ + Size_: 500, }, }, }, @@ -680,23 +689,23 @@ func TestPollComparePreviousResults(t *testing.T) { previousPerTenant: PerTenant{}, previousCompactedPerTenant: PerTenantCompacted{}, currentPerTenant: PerTenant{ - "test": []*backend.BlockMeta{ - {BlockID: zero}, + "test": []*backend_v1.BlockMeta{ + {BlockId: uuidBytes(zero)}, }, }, currentCompactedPerTenant: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: eff}}, + "test": []*backend_v1.CompactedBlockMeta{ + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(eff)}}, }, }, expectedPerTenant: PerTenant{ - "test": []*backend.BlockMeta{ - {BlockID: zero}, + "test": []*backend_v1.BlockMeta{ + {BlockId: uuidBytes(zero)}, }, }, expectedCompactedPerTenant: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: eff}}, + "test": []*backend_v1.CompactedBlockMeta{ + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(eff)}}, }, }, expectedBlockMetaCalls: map[string]map[uuid.UUID]int{ @@ -713,59 +722,59 @@ func TestPollComparePreviousResults(t *testing.T) { { name: "with previous results, meta should be read from only new blocks", previousPerTenant: PerTenant{ - "test": []*backend.BlockMeta{ - {BlockID: zero}, - {BlockID: eff}, + "test": []*backend_v1.BlockMeta{ + {BlockId: uuidBytes(zero)}, + {BlockId: uuidBytes(eff)}, }, }, previousCompactedPerTenant: PerTenantCompacted{}, currentPerTenant: PerTenant{ - "test": []*backend.BlockMeta{ - {BlockID: zero}, - {BlockID: eff}, + "test": []*backend_v1.BlockMeta{ + {BlockId: uuidBytes(zero)}, + {BlockId: uuidBytes(eff)}, }, }, currentCompactedPerTenant: PerTenantCompacted{}, expectedPerTenant: PerTenant{ - "test": []*backend.BlockMeta{ - {BlockID: zero}, - {BlockID: eff}, + "test": []*backend_v1.BlockMeta{ + {BlockId: uuidBytes(zero)}, + {BlockId: uuidBytes(eff)}, }, }, expectedCompactedPerTenant: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{}, + "test": []*backend_v1.CompactedBlockMeta{}, }, expectedBlockMetaCalls: map[string]map[uuid.UUID]int{}, }, { name: "with previous results, blocks that have been compacted since the last poll should be known as compacted", previousPerTenant: PerTenant{ - "test": []*backend.BlockMeta{ - {BlockID: zero}, - {BlockID: aaa}, + "test": []*backend_v1.BlockMeta{ + {BlockId: uuidBytes(zero)}, + {BlockId: uuidBytes(aaa)}, }, }, previousCompactedPerTenant: PerTenantCompacted{}, currentPerTenant: PerTenant{ - "test": []*backend.BlockMeta{ - {BlockID: eff}, + "test": []*backend_v1.BlockMeta{ + {BlockId: uuidBytes(eff)}, }, }, currentCompactedPerTenant: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: zero}}, - {BlockMeta: backend.BlockMeta{BlockID: aaa}}, + "test": []*backend_v1.CompactedBlockMeta{ + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(zero)}}, + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(aaa)}}, }, }, expectedPerTenant: PerTenant{ - "test": []*backend.BlockMeta{ - {BlockID: eff}, + "test": []*backend_v1.BlockMeta{ + {BlockId: uuidBytes(eff)}, }, }, expectedCompactedPerTenant: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: aaa}}, - {BlockMeta: backend.BlockMeta{BlockID: zero}}, + "test": []*backend_v1.CompactedBlockMeta{ + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(aaa)}}, + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(zero)}}, }, }, expectedBlockMetaCalls: map[string]map[uuid.UUID]int{ @@ -784,28 +793,28 @@ func TestPollComparePreviousResults(t *testing.T) { name: "with previous compactions should be known", previousPerTenant: PerTenant{}, previousCompactedPerTenant: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: zero}}, - {BlockMeta: backend.BlockMeta{BlockID: aaa}}, - {BlockMeta: backend.BlockMeta{BlockID: eff}}, + "test": []*backend_v1.CompactedBlockMeta{ + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(zero)}}, + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(aaa)}}, + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(eff)}}, }, }, currentPerTenant: PerTenant{}, currentCompactedPerTenant: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: zero}}, - {BlockMeta: backend.BlockMeta{BlockID: aaa}}, - {BlockMeta: backend.BlockMeta{BlockID: eff}}, + "test": []*backend_v1.CompactedBlockMeta{ + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(zero)}}, + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(aaa)}}, + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(eff)}}, }, }, expectedPerTenant: PerTenant{ - "test": []*backend.BlockMeta{}, + "test": []*backend_v1.BlockMeta{}, }, expectedCompactedPerTenant: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: zero}}, - {BlockMeta: backend.BlockMeta{BlockID: aaa}}, - {BlockMeta: backend.BlockMeta{BlockID: eff}}, + "test": []*backend_v1.CompactedBlockMeta{ + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(zero)}}, + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(aaa)}}, + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(eff)}}, }, }, expectedBlockMetaCalls: map[string]map[uuid.UUID]int{}, @@ -814,8 +823,8 @@ func TestPollComparePreviousResults(t *testing.T) { name: "with previous compactions removed, should be forgotten", previousPerTenant: PerTenant{}, previousCompactedPerTenant: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: zero}}, + "test": []*backend_v1.CompactedBlockMeta{ + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(zero)}}, }, }, currentPerTenant: PerTenant{}, @@ -831,28 +840,28 @@ func TestPollComparePreviousResults(t *testing.T) { readerErr: true, previousPerTenant: PerTenant{}, previousCompactedPerTenant: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: zero}}, - {BlockMeta: backend.BlockMeta{BlockID: aaa}}, - {BlockMeta: backend.BlockMeta{BlockID: eff}}, + "test": []*backend_v1.CompactedBlockMeta{ + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(zero)}}, + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(aaa)}}, + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(eff)}}, }, }, currentPerTenant: PerTenant{}, currentCompactedPerTenant: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: zero}}, - {BlockMeta: backend.BlockMeta{BlockID: aaa}}, - {BlockMeta: backend.BlockMeta{BlockID: eff}}, + "test": []*backend_v1.CompactedBlockMeta{ + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(zero)}}, + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(aaa)}}, + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(eff)}}, }, }, expectedPerTenant: PerTenant{ - "test": []*backend.BlockMeta{}, + "test": []*backend_v1.BlockMeta{}, }, expectedCompactedPerTenant: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: zero}}, - {BlockMeta: backend.BlockMeta{BlockID: aaa}}, - {BlockMeta: backend.BlockMeta{BlockID: eff}}, + "test": []*backend_v1.CompactedBlockMeta{ + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(zero)}}, + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(aaa)}}, + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(eff)}}, }, }, expectedBlockMetaCalls: map[string]map[uuid.UUID]int{}, @@ -863,45 +872,45 @@ func TestPollComparePreviousResults(t *testing.T) { tollerateTenantFailures: 2, readerErr: true, previousPerTenant: PerTenant{ - "test2": []*backend.BlockMeta{ - {BlockID: zero}, - {BlockID: eff}, + "test2": []*backend_v1.BlockMeta{ + {BlockId: uuidBytes(zero)}, + {BlockId: uuidBytes(eff)}, }, }, previousCompactedPerTenant: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: zero}}, - {BlockMeta: backend.BlockMeta{BlockID: aaa}}, - {BlockMeta: backend.BlockMeta{BlockID: eff}}, + "test": []*backend_v1.CompactedBlockMeta{ + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(zero)}}, + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(aaa)}}, + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(eff)}}, }, }, currentPerTenant: PerTenant{ - "test2": []*backend.BlockMeta{ - {BlockID: zero}, - {BlockID: eff}, + "test2": []*backend_v1.BlockMeta{ + {BlockId: uuidBytes(zero)}, + {BlockId: uuidBytes(eff)}, }, }, currentCompactedPerTenant: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: zero}}, - {BlockMeta: backend.BlockMeta{BlockID: aaa}}, - {BlockMeta: backend.BlockMeta{BlockID: eff}}, + "test": []*backend_v1.CompactedBlockMeta{ + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(zero)}}, + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(aaa)}}, + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(eff)}}, }, }, expectedPerTenant: PerTenant{ - "test": []*backend.BlockMeta{}, - "test2": []*backend.BlockMeta{ - {BlockID: zero}, - {BlockID: eff}, + "test": []*backend_v1.BlockMeta{}, + "test2": []*backend_v1.BlockMeta{ + {BlockId: uuidBytes(zero)}, + {BlockId: uuidBytes(eff)}, }, }, expectedCompactedPerTenant: PerTenantCompacted{ - "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: zero}}, - {BlockMeta: backend.BlockMeta{BlockID: aaa}}, - {BlockMeta: backend.BlockMeta{BlockID: eff}}, + "test": []*backend_v1.CompactedBlockMeta{ + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(zero)}}, + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(aaa)}}, + {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(eff)}}, }, - "test2": []*backend.CompactedBlockMeta{}, + "test2": []*backend_v1.CompactedBlockMeta{}, }, expectedBlockMetaCalls: map[string]map[uuid.UUID]int{}, }, @@ -934,12 +943,12 @@ func TestPollComparePreviousResults(t *testing.T) { for tenantID, expectedMetas := range tc.expectedPerTenant { l := metas[tenantID] sort.Slice(l, func(i, j int) bool { - x := bytes.Compare(l[i].BlockID[:], l[j].BlockID[:]) + x := bytes.Compare(l[i].BlockId[:], l[j].BlockId[:]) return x > 0 }) sort.Slice(expectedMetas, func(i, j int) bool { - x := bytes.Compare(expectedMetas[i].BlockID[:], expectedMetas[j].BlockID[:]) + x := bytes.Compare(expectedMetas[i].BlockId[:], expectedMetas[j].BlockId[:]) return x > 0 }) @@ -950,12 +959,12 @@ func TestPollComparePreviousResults(t *testing.T) { for tenantID, expectedCompactedMetas := range tc.expectedCompactedPerTenant { l := compactedMetas[tenantID] sort.Slice(l, func(i, j int) bool { - x := bytes.Compare(l[i].BlockID[:], l[j].BlockID[:]) + x := bytes.Compare(l[i].BlockId[:], l[j].BlockId[:]) return x > 0 }) sort.Slice(expectedCompactedMetas, func(i, j int) bool { - x := bytes.Compare(expectedCompactedMetas[i].BlockID[:], expectedCompactedMetas[j].BlockID[:]) + x := bytes.Compare(expectedCompactedMetas[i].BlockId[:], expectedCompactedMetas[j].BlockId[:]) return x > 0 }) require.Equal(t, expectedCompactedMetas, l) @@ -1032,23 +1041,23 @@ func benchmarkPollTenant(b *testing.B, poller *Poller, tenant string, previous * } } -func newBlockMetas(count int) []*backend.BlockMeta { - metas := make([]*backend.BlockMeta, count) +func newBlockMetas(count int) []*backend_v1.BlockMeta { + metas := make([]*backend_v1.BlockMeta, count) for i := 0; i < count; i++ { - metas[i] = &backend.BlockMeta{ - BlockID: uuid.New(), + metas[i] = &backend_v1.BlockMeta{ + BlockId: []byte(uuid.New().String()), } } return metas } -func newCompactedMetas(count int) []*backend.CompactedBlockMeta { - metas := make([]*backend.CompactedBlockMeta, count) +func newCompactedMetas(count int) []*backend_v1.CompactedBlockMeta { + metas := make([]*backend_v1.CompactedBlockMeta, count) for i := 0; i < count; i++ { - metas[i] = &backend.CompactedBlockMeta{ - BlockMeta: backend.BlockMeta{ - BlockID: uuid.New(), + metas[i] = &backend_v1.CompactedBlockMeta{ + BlockMeta: backend_v1.BlockMeta{ + BlockId: []byte(uuid.New().String()), }, } } @@ -1068,7 +1077,7 @@ func randString(n int) string { func newPerTenant(tenantCount, blockCount int) PerTenant { perTenant := make(PerTenant, tenantCount) - var metas []*backend.BlockMeta + var metas []*backend_v1.BlockMeta var id string for i := 0; i < tenantCount; i++ { metas = newBlockMetas(blockCount) @@ -1081,7 +1090,7 @@ func newPerTenant(tenantCount, blockCount int) PerTenant { func newPerTenantCompacted(tenantCount, blockCount int) PerTenantCompacted { perTenantCompacted := make(PerTenantCompacted) - var metas []*backend.CompactedBlockMeta + var metas []*backend_v1.CompactedBlockMeta var id string for i := 0; i < tenantCount; i++ { metas = newCompactedMetas(blockCount) @@ -1094,7 +1103,9 @@ func newPerTenantCompacted(tenantCount, blockCount int) PerTenantCompacted { func newMockCompactor(list PerTenantCompacted, expectsError bool) backend.Compactor { return &backend.MockCompactor{ - BlockMetaFn: func(blockID uuid.UUID, tenantID string) (*backend.CompactedBlockMeta, error) { + BlockMetaFn: func(blockID uuid.UUID, tenantID string) (*backend_v1.CompactedBlockMeta, error) { + id := []byte(blockID.String()) + if expectsError { return nil, errors.New("err") } @@ -1105,7 +1116,7 @@ func newMockCompactor(list PerTenantCompacted, expectsError bool) backend.Compac } for _, m := range l { - if m.BlockID == blockID { + if bytes.Equal(m.BlockId, id) { return m, nil } } @@ -1140,28 +1151,40 @@ func newMockReader(list PerTenant, compactedList PerTenantCompacted, expectsErro uuids := []uuid.UUID{} compactedUUIDs := []uuid.UUID{} for _, b := range blocks { - uuids = append(uuids, b.BlockID) + + id, err := uuid.ParseBytes(b.BlockId) + if err != nil { + return nil, nil, err + } + + uuids = append(uuids, id) } compactedBlocks := compactedList[tenantID] for _, b := range compactedBlocks { - compactedUUIDs = append(compactedUUIDs, b.BlockID) + id, err := uuid.ParseBytes(b.BlockId) + if err != nil { + return nil, nil, err + } + compactedUUIDs = append(compactedUUIDs, id) } return uuids, compactedUUIDs, nil }, BlockMetaCalls: make(map[string]map[uuid.UUID]int), - BlockMetaFn: func(_ context.Context, blockID uuid.UUID, tenantID string) (*backend.BlockMeta, error) { + BlockMetaFn: func(_ context.Context, blockID uuid.UUID, tenantID string) (*backend_v1.BlockMeta, error) { if expectsError { return nil, errors.New("err") } + id := []byte(blockID.String()) + l, ok := list[tenantID] if !ok { return nil, backend.ErrDoesNotExist } for _, m := range l { - if m.BlockID == blockID { + if bytes.Equal(m.BlockId, id) { return m, nil } } @@ -1178,3 +1201,7 @@ func newBlocklist(metas PerTenant, compactedMetas PerTenantCompacted) *List { return l } + +func uuidBytes(u uuid.UUID) []byte { + return []byte(u.String()) +} From c427c78860bad54ded4d3b91c693de5a49e41627 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Tue, 10 Sep 2024 16:24:52 +0000 Subject: [PATCH 03/71] Functioning blocklist with existing package --- tempodb/blocklist/list.go | 43 ++-- tempodb/blocklist/list_test.go | 350 +++++++++++++++---------------- tempodb/blocklist/poller.go | 41 ++-- tempodb/blocklist/poller_test.go | 343 +++++++++++++++--------------- 4 files changed, 387 insertions(+), 390 deletions(-) diff --git a/tempodb/blocklist/list.go b/tempodb/blocklist/list.go index e45a8b5211c..16b405d7491 100644 --- a/tempodb/blocklist/list.go +++ b/tempodb/blocklist/list.go @@ -5,15 +5,14 @@ import ( "sync" "github.com/google/uuid" - - backend_v1 "github.com/grafana/tempo/tempodb/backend/v1" + "github.com/grafana/tempo/tempodb/backend" ) -// PerTenant is a map of tenant ids to backend_v1.BlockMetas -type PerTenant map[string][]*backend_v1.BlockMeta +// PerTenant is a map of tenant ids to backend.BlockMetas +type PerTenant map[string][]*backend.BlockMeta -// PerTenantCompacted is a map of tenant ids to backend_v1.CompactedBlockMetas -type PerTenantCompacted map[string][]*backend_v1.CompactedBlockMeta +// PerTenantCompacted is a map of tenant ids to backend.CompactedBlockMetas +type PerTenantCompacted map[string][]*backend.CompactedBlockMeta // List controls access to a per tenant blocklist and compacted blocklist type List struct { @@ -53,7 +52,7 @@ func (l *List) Tenants() []string { return tenants } -func (l *List) Metas(tenantID string) []*backend_v1.BlockMeta { +func (l *List) Metas(tenantID string) []*backend.BlockMeta { if tenantID == "" { return nil } @@ -61,12 +60,12 @@ func (l *List) Metas(tenantID string) []*backend_v1.BlockMeta { l.mtx.Lock() defer l.mtx.Unlock() - copiedBlocklist := make([]*backend_v1.BlockMeta, 0, len(l.metas[tenantID])) + copiedBlocklist := make([]*backend.BlockMeta, 0, len(l.metas[tenantID])) copiedBlocklist = append(copiedBlocklist, l.metas[tenantID]...) return copiedBlocklist } -func (l *List) CompactedMetas(tenantID string) []*backend_v1.CompactedBlockMeta { +func (l *List) CompactedMetas(tenantID string) []*backend.CompactedBlockMeta { if tenantID == "" { return nil } @@ -74,7 +73,7 @@ func (l *List) CompactedMetas(tenantID string) []*backend_v1.CompactedBlockMeta l.mtx.Lock() defer l.mtx.Unlock() - copiedBlocklist := make([]*backend_v1.CompactedBlockMeta, 0, len(l.compactedMetas[tenantID])) + copiedBlocklist := make([]*backend.CompactedBlockMeta, 0, len(l.compactedMetas[tenantID])) copiedBlocklist = append(copiedBlocklist, l.compactedMetas[tenantID]...) return copiedBlocklist @@ -103,7 +102,7 @@ func (l *List) ApplyPollResults(m PerTenant, c PerTenantCompacted) { // Update Adds and removes regular or compacted blocks from the in-memory blocklist. // Changes are temporary and will be preserved only for one poll -func (l *List) Update(tenantID string, add []*backend_v1.BlockMeta, remove []*backend_v1.BlockMeta, compactedAdd []*backend_v1.CompactedBlockMeta, compactedRemove []*backend_v1.CompactedBlockMeta) { +func (l *List) Update(tenantID string, add []*backend.BlockMeta, remove []*backend.BlockMeta, compactedAdd []*backend.CompactedBlockMeta, compactedRemove []*backend.CompactedBlockMeta) { if tenantID == "" { return } @@ -126,15 +125,15 @@ func (l *List) Update(tenantID string, add []*backend_v1.BlockMeta, remove []*ba // updateInternal exists to do the work of applying updates to held PerTenant and PerTenantCompacted maps // it must be called under lock -func (l *List) updateInternal(tenantID string, add []*backend_v1.BlockMeta, remove []*backend_v1.BlockMeta, compactedAdd []*backend_v1.CompactedBlockMeta, compactedRemove []*backend_v1.CompactedBlockMeta) { +func (l *List) updateInternal(tenantID string, add []*backend.BlockMeta, remove []*backend.BlockMeta, compactedAdd []*backend.CompactedBlockMeta, compactedRemove []*backend.CompactedBlockMeta) { // ******** Regular blocks ******** blocklist := l.metas[tenantID] matchedRemovals := make(map[uuid.UUID]struct{}) for _, b := range blocklist { for _, rem := range remove { - if bytes.Equal(b.BlockId, rem.BlockId) { - id, err := uuid.ParseBytes(b.BlockId) + if bytes.Equal(b.BlockID, rem.BlockID) { + id, err := uuid.ParseBytes(b.BlockID) if err != nil { // FIXME } @@ -145,12 +144,12 @@ func (l *List) updateInternal(tenantID string, add []*backend_v1.BlockMeta, remo } existingMetas := make(map[uuid.UUID]struct{}) - newblocklist := make([]*backend_v1.BlockMeta, 0, len(blocklist)-len(matchedRemovals)+len(add)) + newblocklist := make([]*backend.BlockMeta, 0, len(blocklist)-len(matchedRemovals)+len(add)) // var id uuid.UUID // var err error // rebuild the blocklist dropping all removals for _, b := range blocklist { - id, err := uuid.ParseBytes(b.BlockId) + id, err := uuid.ParseBytes(b.BlockID) if err != nil { // FIXME: } @@ -161,7 +160,7 @@ func (l *List) updateInternal(tenantID string, add []*backend_v1.BlockMeta, remo } // add new blocks (only if they don't already exist) for _, b := range add { - id, err := uuid.ParseBytes(b.BlockId) + id, err := uuid.ParseBytes(b.BlockID) if err != nil { // FIXME: } @@ -178,11 +177,11 @@ func (l *List) updateInternal(tenantID string, add []*backend_v1.BlockMeta, remo compactedRemovals := map[uuid.UUID]struct{}{} for _, c := range compactedBlocklist { for _, rem := range compactedRemove { - id, err := uuid.ParseBytes(c.BlockId) + id, err := uuid.ParseBytes(c.BlockID) if err != nil { // FIXME: } - if bytes.Equal(c.BlockId, rem.BlockId) { + if bytes.Equal(c.BlockID, rem.BlockID) { compactedRemovals[id] = struct{}{} break } @@ -190,10 +189,10 @@ func (l *List) updateInternal(tenantID string, add []*backend_v1.BlockMeta, remo } existingMetas = make(map[uuid.UUID]struct{}) - newCompactedBlocklist := make([]*backend_v1.CompactedBlockMeta, 0, len(compactedBlocklist)-len(compactedRemovals)+len(compactedAdd)) + newCompactedBlocklist := make([]*backend.CompactedBlockMeta, 0, len(compactedBlocklist)-len(compactedRemovals)+len(compactedAdd)) // rebuild the blocklist dropping all removals for _, b := range compactedBlocklist { - id, err := uuid.ParseBytes(b.BlockId) + id, err := uuid.ParseBytes(b.BlockID) if err != nil { // FIXME: } @@ -203,7 +202,7 @@ func (l *List) updateInternal(tenantID string, add []*backend_v1.BlockMeta, remo } } for _, b := range compactedAdd { - id, err := uuid.ParseBytes(b.BlockId) + id, err := uuid.ParseBytes(b.BlockID) if err != nil { // FIXME: } diff --git a/tempodb/blocklist/list_test.go b/tempodb/blocklist/list_test.go index 65570654281..c1976986d0f 100644 --- a/tempodb/blocklist/list_test.go +++ b/tempodb/blocklist/list_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - backend_v1 "github.com/grafana/tempo/tempodb/backend/v1" + "github.com/grafana/tempo/tempodb/backend" ) const testTenantID = "test" @@ -27,14 +27,14 @@ func TestApplyPollResults(t *testing.T) { { name: "meta only", metas: PerTenant{ - "test": []*backend_v1.BlockMeta{ + "test": []*backend.BlockMeta{ { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, - "test2": []*backend_v1.BlockMeta{ + "test2": []*backend.BlockMeta{ { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, @@ -43,22 +43,22 @@ func TestApplyPollResults(t *testing.T) { { name: "compacted meta only", compacted: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ + "test": []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, - "test2": []*backend_v1.CompactedBlockMeta{ + "test2": []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, }, @@ -68,34 +68,34 @@ func TestApplyPollResults(t *testing.T) { { name: "all", metas: PerTenant{ - "test": []*backend_v1.BlockMeta{ + "test": []*backend.BlockMeta{ { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, - "blerg": []*backend_v1.BlockMeta{ + "blerg": []*backend.BlockMeta{ { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, compacted: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ + "test": []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, - "test2": []*backend_v1.CompactedBlockMeta{ + "test2": []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, }, @@ -127,10 +127,10 @@ func TestApplyPollResults(t *testing.T) { func TestUpdate(t *testing.T) { tests := []struct { name string - existing []*backend_v1.BlockMeta - add []*backend_v1.BlockMeta - remove []*backend_v1.BlockMeta - expected []*backend_v1.BlockMeta + existing []*backend.BlockMeta + add []*backend.BlockMeta + remove []*backend.BlockMeta + expected []*backend.BlockMeta }{ { name: "all nil", @@ -142,37 +142,37 @@ func TestUpdate(t *testing.T) { { name: "add to nil", existing: nil, - add: []*backend_v1.BlockMeta{ + add: []*backend.BlockMeta{ { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, remove: nil, - expected: []*backend_v1.BlockMeta{ + expected: []*backend.BlockMeta{ { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, { name: "add to existing", - existing: []*backend_v1.BlockMeta{ + existing: []*backend.BlockMeta{ { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, - add: []*backend_v1.BlockMeta{ + add: []*backend.BlockMeta{ { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, remove: nil, - expected: []*backend_v1.BlockMeta{ + expected: []*backend.BlockMeta{ { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, }, @@ -180,120 +180,120 @@ func TestUpdate(t *testing.T) { name: "remove from nil", existing: nil, add: nil, - remove: []*backend_v1.BlockMeta{ + remove: []*backend.BlockMeta{ { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, expected: nil, }, { name: "remove nil", - existing: []*backend_v1.BlockMeta{ + existing: []*backend.BlockMeta{ { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, add: nil, remove: nil, - expected: []*backend_v1.BlockMeta{ + expected: []*backend.BlockMeta{ { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, }, { name: "remove existing", - existing: []*backend_v1.BlockMeta{ + existing: []*backend.BlockMeta{ { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, add: nil, - remove: []*backend_v1.BlockMeta{ + remove: []*backend.BlockMeta{ { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, - expected: []*backend_v1.BlockMeta{ + expected: []*backend.BlockMeta{ { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, }, { name: "remove no match", - existing: []*backend_v1.BlockMeta{ + existing: []*backend.BlockMeta{ { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, add: nil, - remove: []*backend_v1.BlockMeta{ + remove: []*backend.BlockMeta{ { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, - expected: []*backend_v1.BlockMeta{ + expected: []*backend.BlockMeta{ { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, { name: "add and remove", - existing: []*backend_v1.BlockMeta{ + existing: []*backend.BlockMeta{ { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, - add: []*backend_v1.BlockMeta{ + add: []*backend.BlockMeta{ { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000003")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000003")), }, }, - remove: []*backend_v1.BlockMeta{ + remove: []*backend.BlockMeta{ { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, - expected: []*backend_v1.BlockMeta{ + expected: []*backend.BlockMeta{ { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000003")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000003")), }, }, }, { name: "add already exists", - existing: []*backend_v1.BlockMeta{ + existing: []*backend.BlockMeta{ { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, - add: []*backend_v1.BlockMeta{ + add: []*backend.BlockMeta{ { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, remove: nil, - expected: []*backend_v1.BlockMeta{ + expected: []*backend.BlockMeta{ { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, { - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, }, @@ -309,7 +309,7 @@ func TestUpdate(t *testing.T) { assert.Equal(t, len(tt.expected), len(l.metas[testTenantID])) for i := range tt.expected { - assert.Equal(t, tt.expected[i].BlockId, l.metas[testTenantID][i].BlockId) + assert.Equal(t, tt.expected[i].BlockID, l.metas[testTenantID][i].BlockID) } }) } @@ -318,10 +318,10 @@ func TestUpdate(t *testing.T) { func TestUpdateCompacted(t *testing.T) { tests := []struct { name string - existing []*backend_v1.CompactedBlockMeta - add []*backend_v1.CompactedBlockMeta - remove []*backend_v1.CompactedBlockMeta - expected []*backend_v1.CompactedBlockMeta + existing []*backend.CompactedBlockMeta + add []*backend.CompactedBlockMeta + remove []*backend.CompactedBlockMeta + expected []*backend.CompactedBlockMeta }{ { name: "all nil", @@ -332,121 +332,121 @@ func TestUpdateCompacted(t *testing.T) { { name: "add to nil", existing: nil, - add: []*backend_v1.CompactedBlockMeta{ + add: []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, - expected: []*backend_v1.CompactedBlockMeta{ + expected: []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, }, { name: "add to existing", - existing: []*backend_v1.CompactedBlockMeta{ + existing: []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, - add: []*backend_v1.CompactedBlockMeta{ + add: []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, }, - expected: []*backend_v1.CompactedBlockMeta{ + expected: []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, }, }, { name: "add already exists", - existing: []*backend_v1.CompactedBlockMeta{ + existing: []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, - add: []*backend_v1.CompactedBlockMeta{ + add: []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, }, - expected: []*backend_v1.CompactedBlockMeta{ + expected: []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, }, }, { name: "add and remove", - existing: []*backend_v1.CompactedBlockMeta{ + existing: []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, }, - add: []*backend_v1.CompactedBlockMeta{ + add: []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000003")), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000003")), }, }, }, - remove: []*backend_v1.CompactedBlockMeta{ + remove: []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), }, }, }, - expected: []*backend_v1.CompactedBlockMeta{ + expected: []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000003")), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000003")), }, }, }, @@ -463,7 +463,7 @@ func TestUpdateCompacted(t *testing.T) { assert.Equal(t, len(tt.expected), len(l.compactedMetas[testTenantID])) for i := range tt.expected { - assert.Equal(t, tt.expected[i].BlockId, l.compactedMetas[testTenantID][i].BlockId) + assert.Equal(t, tt.expected[i].BlockID, l.compactedMetas[testTenantID][i].BlockID) } }) } @@ -482,9 +482,9 @@ func TestUpdatesSaved(t *testing.T) { applyMetas PerTenant applyCompacted PerTenantCompacted updateTenant string - addMetas []*backend_v1.BlockMeta - removeMetas []*backend_v1.BlockMeta - addCompacted []*backend_v1.CompactedBlockMeta + addMetas []*backend.BlockMeta + removeMetas []*backend.BlockMeta + addCompacted []*backend.CompactedBlockMeta expectedTenants []string expectedMetas PerTenant @@ -493,60 +493,60 @@ func TestUpdatesSaved(t *testing.T) { // STEP 1: apply a normal polling data and updates { applyMetas: PerTenant{ - "test": []*backend_v1.BlockMeta{ + "test": []*backend.BlockMeta{ { - BlockId: uuidBytes(one), + BlockID: uuidBytes(one), }, }, }, applyCompacted: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ + "test": []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(oneOhOne), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(oneOhOne), }, }, }, }, updateTenant: "test", - addMetas: []*backend_v1.BlockMeta{ + addMetas: []*backend.BlockMeta{ { - BlockId: uuidBytes(one), + BlockID: uuidBytes(one), }, { - BlockId: uuidBytes(two), + BlockID: uuidBytes(two), }, }, - removeMetas: []*backend_v1.BlockMeta{ + removeMetas: []*backend.BlockMeta{ { - BlockId: uuidBytes(one), + BlockID: uuidBytes(one), }, }, - addCompacted: []*backend_v1.CompactedBlockMeta{ + addCompacted: []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(oneOhTwo), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(oneOhTwo), }, }, }, expectedTenants: []string{"test"}, expectedMetas: PerTenant{ - "test": []*backend_v1.BlockMeta{ + "test": []*backend.BlockMeta{ { - BlockId: uuidBytes(two), + BlockID: uuidBytes(two), }, }, }, expectedCompacted: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ + "test": []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(oneOhOne), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(oneOhOne), }, }, { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(oneOhTwo), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(oneOhTwo), }, }, }, @@ -555,43 +555,43 @@ func TestUpdatesSaved(t *testing.T) { // STEP 2: same polling apply, no update! but expect the same results { applyMetas: PerTenant{ - "test": []*backend_v1.BlockMeta{ + "test": []*backend.BlockMeta{ { - BlockId: uuidBytes(one), + BlockID: uuidBytes(one), }, }, }, applyCompacted: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ + "test": []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(oneOhOne), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(oneOhOne), }, }, }, }, expectedTenants: []string{"test"}, expectedMetas: PerTenant{ - "test": []*backend_v1.BlockMeta{ + "test": []*backend.BlockMeta{ // Even though we have just appled one, it was removed in the previous step, and we we expect not to find it here. // { - // BlockId: one, + // BlockID: one, // }, { - BlockId: uuidBytes(two), + BlockID: uuidBytes(two), }, }, }, expectedCompacted: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ + "test": []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(oneOhOne), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(oneOhOne), }, }, { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(oneOhTwo), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(oneOhTwo), }, }, }, @@ -600,34 +600,34 @@ func TestUpdatesSaved(t *testing.T) { // STEP 3: same polling apply, no update! but this time the update doesn't impact results { applyMetas: PerTenant{ - "test": []*backend_v1.BlockMeta{ + "test": []*backend.BlockMeta{ { - BlockId: uuidBytes(one), + BlockID: uuidBytes(one), }, }, }, applyCompacted: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ + "test": []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(oneOhOne), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(oneOhOne), }, }, }, }, expectedTenants: []string{"test"}, expectedMetas: PerTenant{ - "test": []*backend_v1.BlockMeta{ + "test": []*backend.BlockMeta{ { - BlockId: uuidBytes(one), + BlockID: uuidBytes(one), }, }, }, expectedCompacted: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ + "test": []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(oneOhOne), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(oneOhOne), }, }, }, diff --git a/tempodb/blocklist/poller.go b/tempodb/blocklist/poller.go index 39ae600d063..342a0438847 100644 --- a/tempodb/blocklist/poller.go +++ b/tempodb/blocklist/poller.go @@ -24,7 +24,6 @@ import ( "github.com/grafana/tempo/pkg/boundedwaitgroup" "github.com/grafana/tempo/tempodb/backend" - backend_v1 "github.com/grafana/tempo/tempodb/backend/v1" ) const ( @@ -43,7 +42,7 @@ var ( metricBackendBytes = promauto.NewGaugeVec(prometheus.GaugeOpts{ Namespace: "tempodb", Name: "backend_bytes_total", - Help: "Total number of bytes in the backend.", + Help: "Total number of bytes in the ", }, []string{"tenant", "status"}) metricBlocklistErrors = promauto.NewCounterVec(prometheus.CounterOpts{ Namespace: "tempodb", @@ -182,8 +181,8 @@ func (p *Poller) Do(previous *List) (PerTenant, PerTenantCompacted, error) { var ( consecutiveErrorsRemaining = p.cfg.TolerateConsecutiveErrors - newBlockList = make([]*backend_v1.BlockMeta, 0) - newCompactedBlockList = make([]*backend_v1.CompactedBlockMeta, 0) + newBlockList = make([]*backend.BlockMeta, 0) + newCompactedBlockList = make([]*backend.CompactedBlockMeta, 0) err error ) @@ -242,7 +241,7 @@ func (p *Poller) pollTenantAndCreateIndex( ctx context.Context, tenantID string, previous *List, -) ([]*backend_v1.BlockMeta, []*backend_v1.CompactedBlockMeta, error) { +) ([]*backend.BlockMeta, []*backend.CompactedBlockMeta, error) { derivedCtx, span := tracer.Start(ctx, "Poller.pollTenantAndCreateIndex", trace.WithAttributes(attribute.String("tenant", tenantID))) defer span.End() @@ -309,7 +308,7 @@ func (p *Poller) pollTenantBlocks( ctx context.Context, tenantID string, previous *List, -) ([]*backend_v1.BlockMeta, []*backend_v1.CompactedBlockMeta, error) { +) ([]*backend.BlockMeta, []*backend.CompactedBlockMeta, error) { derivedCtx, span := tracer.Start(ctx, "Poller.pollTenantBlocks") defer span.End() @@ -321,10 +320,10 @@ func (p *Poller) pollTenantBlocks( var ( metas = previous.Metas(tenantID) compactedMetas = previous.CompactedMetas(tenantID) - mm = make(map[uuid.UUID]*backend_v1.BlockMeta, len(metas)) - cm = make(map[uuid.UUID]*backend_v1.CompactedBlockMeta, len(compactedMetas)) - newBlockList = make([]*backend_v1.BlockMeta, 0, len(currentBlockIDs)) - newCompactedBlocklist = make([]*backend_v1.CompactedBlockMeta, 0, len(currentCompactedBlockIDs)) + mm = make(map[uuid.UUID]*backend.BlockMeta, len(metas)) + cm = make(map[uuid.UUID]*backend.CompactedBlockMeta, len(compactedMetas)) + newBlockList = make([]*backend.BlockMeta, 0, len(currentBlockIDs)) + newCompactedBlocklist = make([]*backend.CompactedBlockMeta, 0, len(currentCompactedBlockIDs)) unknownBlockIDs = make(map[uuid.UUID]bool, 1000) ) @@ -332,7 +331,7 @@ func (p *Poller) pollTenantBlocks( span.SetAttributes(attribute.Int("compactedMetas", len(compactedMetas))) for _, i := range metas { - id, err := uuid.ParseBytes(i.BlockId) + id, err := uuid.ParseBytes(i.BlockID) if err != nil { return nil, nil, fmt.Errorf("failed parsing meta UUID bytes: %w", err) } @@ -340,7 +339,7 @@ func (p *Poller) pollTenantBlocks( } for _, i := range compactedMetas { - id, err := uuid.ParseBytes(i.BlockId) + id, err := uuid.ParseBytes(i.BlockID) if err != nil { return nil, nil, fmt.Errorf("failed parsing compacted meta UUID bytes: %w", err) } @@ -396,7 +395,7 @@ func (p *Poller) pollUnknown( ctx context.Context, unknownBlocks map[uuid.UUID]bool, tenantID string, -) ([]*backend_v1.BlockMeta, []*backend_v1.CompactedBlockMeta, error) { +) ([]*backend.BlockMeta, []*backend.CompactedBlockMeta, error) { derivedCtx, span := tracer.Start(ctx, "pollUnknown", trace.WithAttributes( attribute.Int("unknownBlockIDs", len(unknownBlocks)), )) @@ -407,8 +406,8 @@ func (p *Poller) pollUnknown( errs []error mtx sync.Mutex bg = boundedwaitgroup.New(p.cfg.PollConcurrency) - newBlockList = make([]*backend_v1.BlockMeta, 0, len(unknownBlocks)) - newCompactedBlocklist = make([]*backend_v1.CompactedBlockMeta, 0, len(unknownBlocks)) + newBlockList = make([]*backend.BlockMeta, 0, len(unknownBlocks)) + newCompactedBlocklist = make([]*backend.CompactedBlockMeta, 0, len(unknownBlocks)) ) for blockID, compacted := range unknownBlocks { @@ -466,7 +465,7 @@ func (p *Poller) pollBlock( tenantID string, blockID uuid.UUID, compacted bool, -) (*backend_v1.BlockMeta, *backend_v1.CompactedBlockMeta, error) { +) (*backend.BlockMeta, *backend.CompactedBlockMeta, error) { derivedCtx, span := tracer.Start(ctx, "Poller.pollBlock") defer span.End() var err error @@ -474,8 +473,8 @@ func (p *Poller) pollBlock( span.SetAttributes(attribute.String("tenant", tenantID)) span.SetAttributes(attribute.String("block", blockID.String())) - var blockMeta *backend_v1.BlockMeta - var compactedBlockMeta *backend_v1.CompactedBlockMeta + var blockMeta *backend.BlockMeta + var compactedBlockMeta *backend.CompactedBlockMeta if !compacted { blockMeta, err = p.reader.BlockMeta(derivedCtx, blockID, tenantID) @@ -511,7 +510,7 @@ func (p *Poller) tenantIndexBuilder(tenant string) bool { return false } -func (p *Poller) tenantIndexPollError(idx *backend_v1.TenantIndex, err error) error { +func (p *Poller) tenantIndexPollError(idx *backend.TenantIndex, err error) error { if err != nil { return err } @@ -587,8 +586,8 @@ type backendMetaMetrics struct { } func sumTotalBackendMetaMetrics( - blockMeta []*backend_v1.BlockMeta, - compactedBlockMeta []*backend_v1.CompactedBlockMeta, + blockMeta []*backend.BlockMeta, + compactedBlockMeta []*backend.CompactedBlockMeta, ) backendMetaMetrics { var sumTotalObjectsBM int var sumTotalObjectsCBM int diff --git a/tempodb/blocklist/poller_test.go b/tempodb/blocklist/poller_test.go index 58dd95d88d4..41f01e42996 100644 --- a/tempodb/blocklist/poller_test.go +++ b/tempodb/blocklist/poller_test.go @@ -19,7 +19,6 @@ import ( "github.com/stretchr/testify/require" "github.com/grafana/tempo/tempodb/backend" - backend_v1 "github.com/grafana/tempo/tempodb/backend/v1" ) var ( @@ -59,9 +58,9 @@ func TestTenantIndexBuilder(t *testing.T) { { name: "err", list: PerTenant{ - "test": []*backend_v1.BlockMeta{ + "test": []*backend.BlockMeta{ { - BlockId: []byte(one.String()), + BlockID: []byte(one.String()), }, }, }, @@ -70,42 +69,42 @@ func TestTenantIndexBuilder(t *testing.T) { { name: "block meta", list: PerTenant{ - "test": []*backend_v1.BlockMeta{ + "test": []*backend.BlockMeta{ { - BlockId: []byte(one.String()), + BlockID: []byte(one.String()), }, }, }, expectedList: PerTenant{ - "test": []*backend_v1.BlockMeta{ + "test": []*backend.BlockMeta{ { - BlockId: []byte(one.String()), + BlockID: []byte(one.String()), }, }, }, expectedCompactedList: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{}, + "test": []*backend.CompactedBlockMeta{}, }, }, { name: "compacted block meta", compactedList: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ + "test": []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: []byte(one.String()), + BlockMeta: backend.BlockMeta{ + BlockID: []byte(one.String()), }, }, }, }, expectedList: PerTenant{ - "test": []*backend_v1.BlockMeta{}, + "test": []*backend.BlockMeta{}, }, expectedCompactedList: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ + "test": []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: []byte(one.String()), + BlockMeta: backend.BlockMeta{ + BlockID: []byte(one.String()), }, }, }, @@ -114,47 +113,47 @@ func TestTenantIndexBuilder(t *testing.T) { { name: "all", list: PerTenant{ - "test2": []*backend_v1.BlockMeta{ + "test2": []*backend.BlockMeta{ { - BlockId: []byte(three.String()), + BlockID: []byte(three.String()), }, }, - "test": []*backend_v1.BlockMeta{ + "test": []*backend.BlockMeta{ { - BlockId: []byte(two.String()), + BlockID: []byte(two.String()), }, }, }, compactedList: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ + "test": []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: []byte(one.String()), + BlockMeta: backend.BlockMeta{ + BlockID: []byte(one.String()), }, }, }, }, expectedList: PerTenant{ - "test2": []*backend_v1.BlockMeta{ + "test2": []*backend.BlockMeta{ { - BlockId: []byte(three.String()), + BlockID: []byte(three.String()), }, }, - "test": []*backend_v1.BlockMeta{ + "test": []*backend.BlockMeta{ { - BlockId: []byte(two.String()), + BlockID: []byte(two.String()), }, }, }, expectedCompactedList: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ + "test": []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: []byte(one.String()), + BlockMeta: backend.BlockMeta{ + BlockID: []byte(one.String()), }, }, }, - "test2": []*backend_v1.CompactedBlockMeta{}, + "test2": []*backend.CompactedBlockMeta{}, }, }, } @@ -254,16 +253,16 @@ func TestTenantIndexFallback(t *testing.T) { t.Run(tc.name, func(t *testing.T) { c := &backend.MockCompactor{} r := newMockReader(PerTenant{ - "test": []*backend_v1.BlockMeta{}, + "test": []*backend.BlockMeta{}, }, nil, false) w := &backend.MockWriter{} b := newBlocklist(PerTenant{}, PerTenantCompacted{}) - r.(*backend.MockReader).TenantIndexFn = func(_ context.Context, _ string) (*backend_v1.TenantIndex, error) { + r.(*backend.MockReader).TenantIndexFn = func(_ context.Context, _ string) (*backend.TenantIndex, error) { if tc.errorOnCreateTenantIndex { return nil, errors.New("err") } - return &backend_v1.TenantIndex{ + return &backend.TenantIndex{ CreatedAt: time.Now(). Add(-5 * time.Minute), // always make the tenant index 5 minutes old so the above tests can use that for fallback testing @@ -297,59 +296,59 @@ func TestPollBlock(t *testing.T) { list PerTenant compactedList PerTenantCompacted pollTenantID string - pollBlockId uuid.UUID - expectedMeta *backend_v1.BlockMeta - expectedCompactedMeta *backend_v1.CompactedBlockMeta + pollBlockID uuid.UUID + expectedMeta *backend.BlockMeta + expectedCompactedMeta *backend.CompactedBlockMeta expectsError bool }{ { name: "block and tenant don't exist", pollTenantID: "test", - pollBlockId: one, + pollBlockID: one, }, { name: "block exists", pollTenantID: "test", - pollBlockId: one, + pollBlockID: one, list: PerTenant{ - "test": []*backend_v1.BlockMeta{ + "test": []*backend.BlockMeta{ { - BlockId: uuidBytes(one), + BlockID: uuidBytes(one), }, }, }, - expectedMeta: &backend_v1.BlockMeta{ - BlockId: uuidBytes(one), + expectedMeta: &backend.BlockMeta{ + BlockID: uuidBytes(one), }, }, { name: "compactedblock exists", pollTenantID: "test", - pollBlockId: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + pollBlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), compactedList: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ + "test": []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, }, - expectedCompactedMeta: &backend_v1.CompactedBlockMeta{ - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + expectedCompactedMeta: &backend.CompactedBlockMeta{ + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, { name: "errors", pollTenantID: "test", - pollBlockId: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + pollBlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), compactedList: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ + "test": []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ - BlockId: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockMeta: backend.BlockMeta{ + BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), }, }, }, @@ -370,7 +369,7 @@ func TestPollBlock(t *testing.T) { PollFallback: testPollFallback, TenantIndexBuilders: testBuilders, }, &mockJobSharder{}, r, c, w, log.NewNopLogger()) - actualMeta, actualCompactedMeta, err := poller.pollBlock(context.Background(), tc.pollTenantID, tc.pollBlockId, false) + actualMeta, actualCompactedMeta, err := poller.pollBlock(context.Background(), tc.pollTenantID, tc.pollBlockID, false) assert.Equal(t, tc.expectedMeta, actualMeta) assert.Equal(t, tc.expectedCompactedMeta, actualCompactedMeta) @@ -392,19 +391,19 @@ func TestTenantIndexPollError(t *testing.T) { assert.Error(t, p.tenantIndexPollError(nil, errors.New("blerg"))) // tenant index older than 1 minute is stale, error! - assert.Error(t, p.tenantIndexPollError(&backend_v1.TenantIndex{ + assert.Error(t, p.tenantIndexPollError(&backend.TenantIndex{ CreatedAt: time.Now().Add(-5 * time.Minute), }, nil)) // no error, tenant index is within 1 minute - assert.NoError(t, p.tenantIndexPollError(&backend_v1.TenantIndex{ + assert.NoError(t, p.tenantIndexPollError(&backend.TenantIndex{ CreatedAt: time.Now().Add(-time.Second), }, nil)) p = NewPoller(&PollerConfig{}, nil, nil, nil, nil, log.NewNopLogger()) // no error, index is super old but stale tenant index is 0 - assert.NoError(t, p.tenantIndexPollError(&backend_v1.TenantIndex{ + assert.NoError(t, p.tenantIndexPollError(&backend.TenantIndex{ CreatedAt: time.Now().Add(30 * time.Hour), }, nil)) } @@ -423,7 +422,7 @@ func TestBlockListBackendMetrics(t *testing.T) { { name: "total backend objects calculation is correct", list: PerTenant{ - "test": []*backend_v1.BlockMeta{ + "test": []*backend.BlockMeta{ { TotalObjects: 10, }, @@ -436,24 +435,24 @@ func TestBlockListBackendMetrics(t *testing.T) { }, }, compactedList: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ + "test": []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ + BlockMeta: backend.BlockMeta{ TotalObjects: 7, }, }, { - BlockMeta: backend_v1.BlockMeta{ + BlockMeta: backend.BlockMeta{ TotalObjects: 8, }, }, { - BlockMeta: backend_v1.BlockMeta{ + BlockMeta: backend.BlockMeta{ TotalObjects: 5, }, }, { - BlockMeta: backend_v1.BlockMeta{ + BlockMeta: backend.BlockMeta{ TotalObjects: 15, }, }, @@ -468,7 +467,7 @@ func TestBlockListBackendMetrics(t *testing.T) { { name: "total backend bytes calculation is correct", list: PerTenant{ - "test": []*backend_v1.BlockMeta{ + "test": []*backend.BlockMeta{ { Size_: 250, }, @@ -481,24 +480,24 @@ func TestBlockListBackendMetrics(t *testing.T) { }, }, compactedList: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ + "test": []*backend.CompactedBlockMeta{ { - BlockMeta: backend_v1.BlockMeta{ + BlockMeta: backend.BlockMeta{ Size_: 300, }, }, { - BlockMeta: backend_v1.BlockMeta{ + BlockMeta: backend.BlockMeta{ Size_: 200, }, }, { - BlockMeta: backend_v1.BlockMeta{ + BlockMeta: backend.BlockMeta{ Size_: 250, }, }, { - BlockMeta: backend_v1.BlockMeta{ + BlockMeta: backend.BlockMeta{ Size_: 500, }, }, @@ -689,23 +688,23 @@ func TestPollComparePreviousResults(t *testing.T) { previousPerTenant: PerTenant{}, previousCompactedPerTenant: PerTenantCompacted{}, currentPerTenant: PerTenant{ - "test": []*backend_v1.BlockMeta{ - {BlockId: uuidBytes(zero)}, + "test": []*backend.BlockMeta{ + {BlockID: uuidBytes(zero)}, }, }, currentCompactedPerTenant: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(eff)}}, + "test": []*backend.CompactedBlockMeta{ + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(eff)}}, }, }, expectedPerTenant: PerTenant{ - "test": []*backend_v1.BlockMeta{ - {BlockId: uuidBytes(zero)}, + "test": []*backend.BlockMeta{ + {BlockID: uuidBytes(zero)}, }, }, expectedCompactedPerTenant: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(eff)}}, + "test": []*backend.CompactedBlockMeta{ + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(eff)}}, }, }, expectedBlockMetaCalls: map[string]map[uuid.UUID]int{ @@ -722,59 +721,59 @@ func TestPollComparePreviousResults(t *testing.T) { { name: "with previous results, meta should be read from only new blocks", previousPerTenant: PerTenant{ - "test": []*backend_v1.BlockMeta{ - {BlockId: uuidBytes(zero)}, - {BlockId: uuidBytes(eff)}, + "test": []*backend.BlockMeta{ + {BlockID: uuidBytes(zero)}, + {BlockID: uuidBytes(eff)}, }, }, previousCompactedPerTenant: PerTenantCompacted{}, currentPerTenant: PerTenant{ - "test": []*backend_v1.BlockMeta{ - {BlockId: uuidBytes(zero)}, - {BlockId: uuidBytes(eff)}, + "test": []*backend.BlockMeta{ + {BlockID: uuidBytes(zero)}, + {BlockID: uuidBytes(eff)}, }, }, currentCompactedPerTenant: PerTenantCompacted{}, expectedPerTenant: PerTenant{ - "test": []*backend_v1.BlockMeta{ - {BlockId: uuidBytes(zero)}, - {BlockId: uuidBytes(eff)}, + "test": []*backend.BlockMeta{ + {BlockID: uuidBytes(zero)}, + {BlockID: uuidBytes(eff)}, }, }, expectedCompactedPerTenant: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{}, + "test": []*backend.CompactedBlockMeta{}, }, expectedBlockMetaCalls: map[string]map[uuid.UUID]int{}, }, { name: "with previous results, blocks that have been compacted since the last poll should be known as compacted", previousPerTenant: PerTenant{ - "test": []*backend_v1.BlockMeta{ - {BlockId: uuidBytes(zero)}, - {BlockId: uuidBytes(aaa)}, + "test": []*backend.BlockMeta{ + {BlockID: uuidBytes(zero)}, + {BlockID: uuidBytes(aaa)}, }, }, previousCompactedPerTenant: PerTenantCompacted{}, currentPerTenant: PerTenant{ - "test": []*backend_v1.BlockMeta{ - {BlockId: uuidBytes(eff)}, + "test": []*backend.BlockMeta{ + {BlockID: uuidBytes(eff)}, }, }, currentCompactedPerTenant: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(zero)}}, - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(aaa)}}, + "test": []*backend.CompactedBlockMeta{ + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(zero)}}, + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(aaa)}}, }, }, expectedPerTenant: PerTenant{ - "test": []*backend_v1.BlockMeta{ - {BlockId: uuidBytes(eff)}, + "test": []*backend.BlockMeta{ + {BlockID: uuidBytes(eff)}, }, }, expectedCompactedPerTenant: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(aaa)}}, - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(zero)}}, + "test": []*backend.CompactedBlockMeta{ + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(aaa)}}, + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(zero)}}, }, }, expectedBlockMetaCalls: map[string]map[uuid.UUID]int{ @@ -793,28 +792,28 @@ func TestPollComparePreviousResults(t *testing.T) { name: "with previous compactions should be known", previousPerTenant: PerTenant{}, previousCompactedPerTenant: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(zero)}}, - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(aaa)}}, - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(eff)}}, + "test": []*backend.CompactedBlockMeta{ + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(zero)}}, + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(aaa)}}, + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(eff)}}, }, }, currentPerTenant: PerTenant{}, currentCompactedPerTenant: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(zero)}}, - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(aaa)}}, - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(eff)}}, + "test": []*backend.CompactedBlockMeta{ + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(zero)}}, + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(aaa)}}, + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(eff)}}, }, }, expectedPerTenant: PerTenant{ - "test": []*backend_v1.BlockMeta{}, + "test": []*backend.BlockMeta{}, }, expectedCompactedPerTenant: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(zero)}}, - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(aaa)}}, - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(eff)}}, + "test": []*backend.CompactedBlockMeta{ + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(zero)}}, + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(aaa)}}, + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(eff)}}, }, }, expectedBlockMetaCalls: map[string]map[uuid.UUID]int{}, @@ -823,8 +822,8 @@ func TestPollComparePreviousResults(t *testing.T) { name: "with previous compactions removed, should be forgotten", previousPerTenant: PerTenant{}, previousCompactedPerTenant: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(zero)}}, + "test": []*backend.CompactedBlockMeta{ + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(zero)}}, }, }, currentPerTenant: PerTenant{}, @@ -840,28 +839,28 @@ func TestPollComparePreviousResults(t *testing.T) { readerErr: true, previousPerTenant: PerTenant{}, previousCompactedPerTenant: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(zero)}}, - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(aaa)}}, - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(eff)}}, + "test": []*backend.CompactedBlockMeta{ + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(zero)}}, + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(aaa)}}, + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(eff)}}, }, }, currentPerTenant: PerTenant{}, currentCompactedPerTenant: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(zero)}}, - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(aaa)}}, - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(eff)}}, + "test": []*backend.CompactedBlockMeta{ + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(zero)}}, + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(aaa)}}, + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(eff)}}, }, }, expectedPerTenant: PerTenant{ - "test": []*backend_v1.BlockMeta{}, + "test": []*backend.BlockMeta{}, }, expectedCompactedPerTenant: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(zero)}}, - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(aaa)}}, - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(eff)}}, + "test": []*backend.CompactedBlockMeta{ + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(zero)}}, + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(aaa)}}, + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(eff)}}, }, }, expectedBlockMetaCalls: map[string]map[uuid.UUID]int{}, @@ -872,45 +871,45 @@ func TestPollComparePreviousResults(t *testing.T) { tollerateTenantFailures: 2, readerErr: true, previousPerTenant: PerTenant{ - "test2": []*backend_v1.BlockMeta{ - {BlockId: uuidBytes(zero)}, - {BlockId: uuidBytes(eff)}, + "test2": []*backend.BlockMeta{ + {BlockID: uuidBytes(zero)}, + {BlockID: uuidBytes(eff)}, }, }, previousCompactedPerTenant: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(zero)}}, - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(aaa)}}, - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(eff)}}, + "test": []*backend.CompactedBlockMeta{ + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(zero)}}, + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(aaa)}}, + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(eff)}}, }, }, currentPerTenant: PerTenant{ - "test2": []*backend_v1.BlockMeta{ - {BlockId: uuidBytes(zero)}, - {BlockId: uuidBytes(eff)}, + "test2": []*backend.BlockMeta{ + {BlockID: uuidBytes(zero)}, + {BlockID: uuidBytes(eff)}, }, }, currentCompactedPerTenant: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(zero)}}, - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(aaa)}}, - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(eff)}}, + "test": []*backend.CompactedBlockMeta{ + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(zero)}}, + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(aaa)}}, + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(eff)}}, }, }, expectedPerTenant: PerTenant{ - "test": []*backend_v1.BlockMeta{}, - "test2": []*backend_v1.BlockMeta{ - {BlockId: uuidBytes(zero)}, - {BlockId: uuidBytes(eff)}, + "test": []*backend.BlockMeta{}, + "test2": []*backend.BlockMeta{ + {BlockID: uuidBytes(zero)}, + {BlockID: uuidBytes(eff)}, }, }, expectedCompactedPerTenant: PerTenantCompacted{ - "test": []*backend_v1.CompactedBlockMeta{ - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(zero)}}, - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(aaa)}}, - {BlockMeta: backend_v1.BlockMeta{BlockId: uuidBytes(eff)}}, + "test": []*backend.CompactedBlockMeta{ + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(zero)}}, + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(aaa)}}, + {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(eff)}}, }, - "test2": []*backend_v1.CompactedBlockMeta{}, + "test2": []*backend.CompactedBlockMeta{}, }, expectedBlockMetaCalls: map[string]map[uuid.UUID]int{}, }, @@ -943,12 +942,12 @@ func TestPollComparePreviousResults(t *testing.T) { for tenantID, expectedMetas := range tc.expectedPerTenant { l := metas[tenantID] sort.Slice(l, func(i, j int) bool { - x := bytes.Compare(l[i].BlockId[:], l[j].BlockId[:]) + x := bytes.Compare(l[i].BlockID[:], l[j].BlockID[:]) return x > 0 }) sort.Slice(expectedMetas, func(i, j int) bool { - x := bytes.Compare(expectedMetas[i].BlockId[:], expectedMetas[j].BlockId[:]) + x := bytes.Compare(expectedMetas[i].BlockID[:], expectedMetas[j].BlockID[:]) return x > 0 }) @@ -959,12 +958,12 @@ func TestPollComparePreviousResults(t *testing.T) { for tenantID, expectedCompactedMetas := range tc.expectedCompactedPerTenant { l := compactedMetas[tenantID] sort.Slice(l, func(i, j int) bool { - x := bytes.Compare(l[i].BlockId[:], l[j].BlockId[:]) + x := bytes.Compare(l[i].BlockID[:], l[j].BlockID[:]) return x > 0 }) sort.Slice(expectedCompactedMetas, func(i, j int) bool { - x := bytes.Compare(expectedCompactedMetas[i].BlockId[:], expectedCompactedMetas[j].BlockId[:]) + x := bytes.Compare(expectedCompactedMetas[i].BlockID[:], expectedCompactedMetas[j].BlockID[:]) return x > 0 }) require.Equal(t, expectedCompactedMetas, l) @@ -1041,23 +1040,23 @@ func benchmarkPollTenant(b *testing.B, poller *Poller, tenant string, previous * } } -func newBlockMetas(count int) []*backend_v1.BlockMeta { - metas := make([]*backend_v1.BlockMeta, count) +func newBlockMetas(count int) []*backend.BlockMeta { + metas := make([]*backend.BlockMeta, count) for i := 0; i < count; i++ { - metas[i] = &backend_v1.BlockMeta{ - BlockId: []byte(uuid.New().String()), + metas[i] = &backend.BlockMeta{ + BlockID: []byte(uuid.New().String()), } } return metas } -func newCompactedMetas(count int) []*backend_v1.CompactedBlockMeta { - metas := make([]*backend_v1.CompactedBlockMeta, count) +func newCompactedMetas(count int) []*backend.CompactedBlockMeta { + metas := make([]*backend.CompactedBlockMeta, count) for i := 0; i < count; i++ { - metas[i] = &backend_v1.CompactedBlockMeta{ - BlockMeta: backend_v1.BlockMeta{ - BlockId: []byte(uuid.New().String()), + metas[i] = &backend.CompactedBlockMeta{ + BlockMeta: backend.BlockMeta{ + BlockID: []byte(uuid.New().String()), }, } } @@ -1077,7 +1076,7 @@ func randString(n int) string { func newPerTenant(tenantCount, blockCount int) PerTenant { perTenant := make(PerTenant, tenantCount) - var metas []*backend_v1.BlockMeta + var metas []*backend.BlockMeta var id string for i := 0; i < tenantCount; i++ { metas = newBlockMetas(blockCount) @@ -1090,7 +1089,7 @@ func newPerTenant(tenantCount, blockCount int) PerTenant { func newPerTenantCompacted(tenantCount, blockCount int) PerTenantCompacted { perTenantCompacted := make(PerTenantCompacted) - var metas []*backend_v1.CompactedBlockMeta + var metas []*backend.CompactedBlockMeta var id string for i := 0; i < tenantCount; i++ { metas = newCompactedMetas(blockCount) @@ -1103,7 +1102,7 @@ func newPerTenantCompacted(tenantCount, blockCount int) PerTenantCompacted { func newMockCompactor(list PerTenantCompacted, expectsError bool) backend.Compactor { return &backend.MockCompactor{ - BlockMetaFn: func(blockID uuid.UUID, tenantID string) (*backend_v1.CompactedBlockMeta, error) { + BlockMetaFn: func(blockID uuid.UUID, tenantID string) (*backend.CompactedBlockMeta, error) { id := []byte(blockID.String()) if expectsError { @@ -1116,7 +1115,7 @@ func newMockCompactor(list PerTenantCompacted, expectsError bool) backend.Compac } for _, m := range l { - if bytes.Equal(m.BlockId, id) { + if bytes.Equal(m.BlockID, id) { return m, nil } } @@ -1152,7 +1151,7 @@ func newMockReader(list PerTenant, compactedList PerTenantCompacted, expectsErro compactedUUIDs := []uuid.UUID{} for _, b := range blocks { - id, err := uuid.ParseBytes(b.BlockId) + id, err := uuid.ParseBytes(b.BlockID) if err != nil { return nil, nil, err } @@ -1161,7 +1160,7 @@ func newMockReader(list PerTenant, compactedList PerTenantCompacted, expectsErro } compactedBlocks := compactedList[tenantID] for _, b := range compactedBlocks { - id, err := uuid.ParseBytes(b.BlockId) + id, err := uuid.ParseBytes(b.BlockID) if err != nil { return nil, nil, err } @@ -1171,7 +1170,7 @@ func newMockReader(list PerTenant, compactedList PerTenantCompacted, expectsErro return uuids, compactedUUIDs, nil }, BlockMetaCalls: make(map[string]map[uuid.UUID]int), - BlockMetaFn: func(_ context.Context, blockID uuid.UUID, tenantID string) (*backend_v1.BlockMeta, error) { + BlockMetaFn: func(_ context.Context, blockID uuid.UUID, tenantID string) (*backend.BlockMeta, error) { if expectsError { return nil, errors.New("err") } @@ -1184,7 +1183,7 @@ func newMockReader(list PerTenant, compactedList PerTenantCompacted, expectsErro } for _, m := range l { - if bytes.Equal(m.BlockId, id) { + if bytes.Equal(m.BlockID, id) { return m, nil } } From c9c6c2411dd17966eb5016ba1f9e328162cc5bd0 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Tue, 10 Sep 2024 16:25:24 +0000 Subject: [PATCH 04/71] Generate proto to existing package --- Makefile | 3 +- tempodb/backend/v1/v1.pb.go | 1508 ----------------------------------- tempodb/backend/v1/v1.proto | 16 +- 3 files changed, 13 insertions(+), 1514 deletions(-) delete mode 100644 tempodb/backend/v1/v1.pb.go diff --git a/Makefile b/Makefile index 15d88adb4bf..38683be310b 100644 --- a/Makefile +++ b/Makefile @@ -223,6 +223,7 @@ PROTO_INTERMEDIATE_DIR = pkg/.patched-proto PROTO_INCLUDES = -I$(PROTO_INTERMEDIATE_DIR) PROTO_GEN = $(PROTOC) $(PROTO_INCLUDES) --gogofaster_out=plugins=grpc,paths=source_relative:$(2) $(1) PROTO_GEN_WITH_VENDOR = $(PROTOC) $(PROTO_INCLUDES) -Ivendor -Ivendor/github.com/gogo/protobuf -Ipkg/tempopb --gogofaster_out=plugins=grpc,paths=source_relative:$(2) $(1) +PROTO_GEN_WITHOUT_RELATIVE = $(PROTOC) $(PROTO_INCLUDES) --gogofaster_out=plugins=grpc:$(2) $(1) .PHONY: gen-proto gen-proto: ## Generate proto files @@ -264,7 +265,7 @@ gen-proto: ## Generate proto files $(call PROTO_GEN,$(PROTO_INTERMEDIATE_DIR)/resource/v1/resource.proto,./pkg/tempopb/) $(call PROTO_GEN,$(PROTO_INTERMEDIATE_DIR)/trace/v1/trace.proto,./pkg/tempopb/) $(call PROTO_GEN,pkg/tempopb/tempo.proto,./) - $(call PROTO_GEN,tempodb/backend/v1/v1.proto,./) + $(call PROTO_GEN_WITHOUT_RELATIVE,tempodb/backend/v1/v1.proto,./) $(call PROTO_GEN_WITH_VENDOR,modules/frontend/v1/frontendv1pb/frontend.proto,./) rm -rf $(PROTO_INTERMEDIATE_DIR) diff --git a/tempodb/backend/v1/v1.pb.go b/tempodb/backend/v1/v1.pb.go deleted file mode 100644 index b6ee6b0da3b..00000000000 --- a/tempodb/backend/v1/v1.pb.go +++ /dev/null @@ -1,1508 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: tempodb/backend/v1/v1.proto - -package v1 - -import ( - fmt "fmt" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" - github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" - tempopb "github.com/grafana/tempo/pkg/tempopb" - _ "google.golang.org/protobuf/types/known/timestamppb" - io "io" - math "math" - math_bits "math/bits" - time "time" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf -var _ = time.Kitchen - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -type BlockMeta struct { - Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"format"` - BlockId []byte `protobuf:"bytes,2,opt,name=block_id,json=blockId,proto3" json:"blockID"` - TenantId string `protobuf:"bytes,5,opt,name=tenant_id,json=tenantId,proto3" json:"tenantID"` - StartTime time.Time `protobuf:"bytes,6,opt,name=start_time,json=startTime,proto3,stdtime" json:"startTime"` - EndTime time.Time `protobuf:"bytes,7,opt,name=end_time,json=endTime,proto3,stdtime" json:"endTime"` - TotalObjects int32 `protobuf:"varint,8,opt,name=total_objects,json=totalObjects,proto3" json:"totalObjects"` - Size_ uint64 `protobuf:"varint,9,opt,name=size,proto3" json:"size,omitempty"` - CompactionLevel uint32 `protobuf:"varint,10,opt,name=compaction_level,json=compactionLevel,proto3" json:"compactionLevel"` - Encoding uint32 `protobuf:"varint,11,opt,name=encoding,proto3" json:"encoding,omitempty"` - IndexPageSize uint32 `protobuf:"varint,12,opt,name=index_page_size,json=indexPageSize,proto3" json:"indexPageSize"` - TotalRecords uint32 `protobuf:"varint,13,opt,name=total_records,json=totalRecords,proto3" json:"totalRecords"` - DataEncoding string `protobuf:"bytes,14,opt,name=data_encoding,json=dataEncoding,proto3" json:"dataEncoding"` - BloomShardCount uint32 `protobuf:"varint,15,opt,name=bloom_shard_count,json=bloomShardCount,proto3" json:"bloomShards"` - FooterSize uint32 `protobuf:"varint,16,opt,name=footer_size,json=footerSize,proto3" json:"footerSize"` - DedicatedColumns []*tempopb.DedicatedColumn `protobuf:"bytes,17,rep,name=dedicated_columns,json=dedicatedColumns,proto3" json:"dedicatedColumns,omitempty"` - ReplicationFactor uint32 `protobuf:"varint,18,opt,name=replication_factor,json=replicationFactor,proto3" json:"replicationFactor,omitempty"` -} - -func (m *BlockMeta) Reset() { *m = BlockMeta{} } -func (m *BlockMeta) String() string { return proto.CompactTextString(m) } -func (*BlockMeta) ProtoMessage() {} -func (*BlockMeta) Descriptor() ([]byte, []int) { - return fileDescriptor_6bc10ae735c1a340, []int{0} -} -func (m *BlockMeta) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *BlockMeta) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_BlockMeta.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *BlockMeta) XXX_Merge(src proto.Message) { - xxx_messageInfo_BlockMeta.Merge(m, src) -} -func (m *BlockMeta) XXX_Size() int { - return m.Size() -} -func (m *BlockMeta) XXX_DiscardUnknown() { - xxx_messageInfo_BlockMeta.DiscardUnknown(m) -} - -var xxx_messageInfo_BlockMeta proto.InternalMessageInfo - -func (m *BlockMeta) GetVersion() string { - if m != nil { - return m.Version - } - return "" -} - -func (m *BlockMeta) GetBlockId() []byte { - if m != nil { - return m.BlockId - } - return nil -} - -func (m *BlockMeta) GetTenantId() string { - if m != nil { - return m.TenantId - } - return "" -} - -func (m *BlockMeta) GetStartTime() time.Time { - if m != nil { - return m.StartTime - } - return time.Time{} -} - -func (m *BlockMeta) GetEndTime() time.Time { - if m != nil { - return m.EndTime - } - return time.Time{} -} - -func (m *BlockMeta) GetTotalObjects() int32 { - if m != nil { - return m.TotalObjects - } - return 0 -} - -func (m *BlockMeta) GetSize_() uint64 { - if m != nil { - return m.Size_ - } - return 0 -} - -func (m *BlockMeta) GetCompactionLevel() uint32 { - if m != nil { - return m.CompactionLevel - } - return 0 -} - -func (m *BlockMeta) GetEncoding() uint32 { - if m != nil { - return m.Encoding - } - return 0 -} - -func (m *BlockMeta) GetIndexPageSize() uint32 { - if m != nil { - return m.IndexPageSize - } - return 0 -} - -func (m *BlockMeta) GetTotalRecords() uint32 { - if m != nil { - return m.TotalRecords - } - return 0 -} - -func (m *BlockMeta) GetDataEncoding() string { - if m != nil { - return m.DataEncoding - } - return "" -} - -func (m *BlockMeta) GetBloomShardCount() uint32 { - if m != nil { - return m.BloomShardCount - } - return 0 -} - -func (m *BlockMeta) GetFooterSize() uint32 { - if m != nil { - return m.FooterSize - } - return 0 -} - -func (m *BlockMeta) GetDedicatedColumns() []*tempopb.DedicatedColumn { - if m != nil { - return m.DedicatedColumns - } - return nil -} - -func (m *BlockMeta) GetReplicationFactor() uint32 { - if m != nil { - return m.ReplicationFactor - } - return 0 -} - -type CompactedBlockMeta struct { - BlockMeta `protobuf:"bytes,1,opt,name=block_meta,json=blockMeta,proto3,embedded=block_meta" json:"block_meta"` - CompactedTime time.Time `protobuf:"bytes,2,opt,name=compacted_time,json=compactedTime,proto3,stdtime" json:"compacted_time"` -} - -func (m *CompactedBlockMeta) Reset() { *m = CompactedBlockMeta{} } -func (m *CompactedBlockMeta) String() string { return proto.CompactTextString(m) } -func (*CompactedBlockMeta) ProtoMessage() {} -func (*CompactedBlockMeta) Descriptor() ([]byte, []int) { - return fileDescriptor_6bc10ae735c1a340, []int{1} -} -func (m *CompactedBlockMeta) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *CompactedBlockMeta) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_CompactedBlockMeta.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *CompactedBlockMeta) XXX_Merge(src proto.Message) { - xxx_messageInfo_CompactedBlockMeta.Merge(m, src) -} -func (m *CompactedBlockMeta) XXX_Size() int { - return m.Size() -} -func (m *CompactedBlockMeta) XXX_DiscardUnknown() { - xxx_messageInfo_CompactedBlockMeta.DiscardUnknown(m) -} - -var xxx_messageInfo_CompactedBlockMeta proto.InternalMessageInfo - -func (m *CompactedBlockMeta) GetCompactedTime() time.Time { - if m != nil { - return m.CompactedTime - } - return time.Time{} -} - -type TenantIndex struct { - CreatedAt time.Time `protobuf:"bytes,1,opt,name=created_at,json=createdAt,proto3,stdtime" json:"created_at"` - Meta []*BlockMeta `protobuf:"bytes,2,rep,name=meta,proto3" json:"meta,omitempty"` - CompactedMeta []*CompactedBlockMeta `protobuf:"bytes,3,rep,name=compacted_meta,json=compactedMeta,proto3" json:"compacted_meta,omitempty"` -} - -func (m *TenantIndex) Reset() { *m = TenantIndex{} } -func (m *TenantIndex) String() string { return proto.CompactTextString(m) } -func (*TenantIndex) ProtoMessage() {} -func (*TenantIndex) Descriptor() ([]byte, []int) { - return fileDescriptor_6bc10ae735c1a340, []int{2} -} -func (m *TenantIndex) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *TenantIndex) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_TenantIndex.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *TenantIndex) XXX_Merge(src proto.Message) { - xxx_messageInfo_TenantIndex.Merge(m, src) -} -func (m *TenantIndex) XXX_Size() int { - return m.Size() -} -func (m *TenantIndex) XXX_DiscardUnknown() { - xxx_messageInfo_TenantIndex.DiscardUnknown(m) -} - -var xxx_messageInfo_TenantIndex proto.InternalMessageInfo - -func (m *TenantIndex) GetCreatedAt() time.Time { - if m != nil { - return m.CreatedAt - } - return time.Time{} -} - -func (m *TenantIndex) GetMeta() []*BlockMeta { - if m != nil { - return m.Meta - } - return nil -} - -func (m *TenantIndex) GetCompactedMeta() []*CompactedBlockMeta { - if m != nil { - return m.CompactedMeta - } - return nil -} - -func init() { - proto.RegisterType((*BlockMeta)(nil), "backend.v1.BlockMeta") - proto.RegisterType((*CompactedBlockMeta)(nil), "backend.v1.CompactedBlockMeta") - proto.RegisterType((*TenantIndex)(nil), "backend.v1.TenantIndex") -} - -func init() { proto.RegisterFile("tempodb/backend/v1/v1.proto", fileDescriptor_6bc10ae735c1a340) } - -var fileDescriptor_6bc10ae735c1a340 = []byte{ - // 767 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0x4f, 0x6b, 0xe3, 0x46, - 0x14, 0xb7, 0xb2, 0xd9, 0xd8, 0x1e, 0xd9, 0xb1, 0x3d, 0xcb, 0x52, 0xe1, 0x05, 0xc9, 0x84, 0x52, - 0xbc, 0xb4, 0x95, 0x48, 0x4a, 0x0f, 0xa5, 0x10, 0xa8, 0x9c, 0x14, 0xd2, 0xbf, 0x41, 0xc9, 0xa9, - 0x17, 0x31, 0xd2, 0x8c, 0x15, 0x35, 0x92, 0x46, 0x48, 0x63, 0xd3, 0xe6, 0x53, 0xe4, 0xd6, 0x73, - 0xbf, 0x4b, 0x0f, 0x39, 0xe6, 0xd8, 0x93, 0x5a, 0x92, 0x9b, 0x3e, 0x45, 0x99, 0x27, 0xd9, 0xb2, - 0x93, 0x42, 0xf6, 0xe4, 0x79, 0xbf, 0x3f, 0x4f, 0xf3, 0x9b, 0xf1, 0x1b, 0xf4, 0x4e, 0xb0, 0x38, - 0xe5, 0xd4, 0xb3, 0x3c, 0xe2, 0x5f, 0xb3, 0x84, 0x5a, 0xcb, 0x43, 0x6b, 0x79, 0x68, 0xa6, 0x19, - 0x17, 0x1c, 0xa3, 0x1a, 0x34, 0x97, 0x87, 0xe3, 0x8f, 0xd2, 0xeb, 0xc0, 0x02, 0x71, 0xea, 0x55, - 0xbf, 0x95, 0x68, 0x6c, 0x04, 0x9c, 0x07, 0x11, 0xb3, 0xa0, 0xf2, 0x16, 0x73, 0x4b, 0x84, 0x31, - 0xcb, 0x05, 0x89, 0xd3, 0x5a, 0xf0, 0x79, 0x10, 0x8a, 0xab, 0x85, 0x67, 0xfa, 0x3c, 0xb6, 0x02, - 0x1e, 0xf0, 0x46, 0x29, 0x2b, 0x28, 0x60, 0x55, 0xc9, 0x0f, 0xfe, 0x68, 0xa3, 0xae, 0x1d, 0x71, - 0xff, 0xfa, 0x47, 0x26, 0x08, 0xfe, 0x18, 0xb5, 0x97, 0x2c, 0xcb, 0x43, 0x9e, 0x68, 0xca, 0x44, - 0x99, 0x76, 0x6d, 0x54, 0x16, 0xc6, 0xde, 0x9c, 0x67, 0x31, 0x11, 0xce, 0x8a, 0xc2, 0x9f, 0xa0, - 0x8e, 0x27, 0x2d, 0x6e, 0x48, 0xb5, 0x9d, 0x89, 0x32, 0xed, 0xd9, 0x6a, 0x59, 0x18, 0x6d, 0xc0, - 0xce, 0x4e, 0x9c, 0x7a, 0x41, 0xf1, 0x7b, 0xd4, 0x15, 0x2c, 0x21, 0x89, 0x90, 0xc2, 0xd7, 0xd0, - 0xaf, 0x57, 0x16, 0x46, 0xa7, 0x02, 0xcf, 0x4e, 0x9c, 0xd5, 0x8a, 0xe2, 0x73, 0x84, 0x72, 0x41, - 0x32, 0xe1, 0xca, 0x38, 0xda, 0xde, 0x44, 0x99, 0xaa, 0x47, 0x63, 0xb3, 0xca, 0x6a, 0xae, 0x12, - 0x98, 0x97, 0xab, 0xac, 0xf6, 0xdb, 0xbb, 0xc2, 0x68, 0x95, 0x85, 0xd1, 0x05, 0x97, 0xc4, 0x6f, - 0xff, 0x31, 0x14, 0xa7, 0x29, 0xf1, 0x77, 0xa8, 0xc3, 0x12, 0x5a, 0xf5, 0x6b, 0xbf, 0xd8, 0xef, - 0x4d, 0xdd, 0xaf, 0xcd, 0x12, 0xba, 0xee, 0xb6, 0x2a, 0xf0, 0x97, 0xa8, 0x2f, 0xb8, 0x20, 0x91, - 0xcb, 0xbd, 0x5f, 0x99, 0x2f, 0x72, 0xad, 0x33, 0x51, 0xa6, 0xaf, 0xed, 0x61, 0x59, 0x18, 0x3d, - 0x20, 0x7e, 0xae, 0x70, 0x67, 0xab, 0xc2, 0x18, 0xed, 0xe6, 0xe1, 0x0d, 0xd3, 0xba, 0x13, 0x65, - 0xba, 0xeb, 0xc0, 0x1a, 0x1f, 0xa3, 0xa1, 0xcf, 0xe3, 0x94, 0xf8, 0x22, 0xe4, 0x89, 0x1b, 0xb1, - 0x25, 0x8b, 0x34, 0x34, 0x51, 0xa6, 0x7d, 0xfb, 0x4d, 0x59, 0x18, 0x83, 0x86, 0xfb, 0x41, 0x52, - 0xce, 0x53, 0x00, 0x8f, 0x65, 0x2c, 0x9f, 0xd3, 0x30, 0x09, 0x34, 0x55, 0xfa, 0x9c, 0x75, 0x8d, - 0xbf, 0x42, 0x83, 0x30, 0xa1, 0xec, 0x37, 0x37, 0x25, 0x01, 0x73, 0xe1, 0xd3, 0x3d, 0x68, 0x3d, - 0x2a, 0x0b, 0xa3, 0x0f, 0xd4, 0x39, 0x09, 0xd8, 0x45, 0x78, 0xc3, 0x9c, 0xed, 0xb2, 0x49, 0x98, - 0x31, 0x9f, 0x67, 0x34, 0xd7, 0xfa, 0x60, 0x6c, 0x12, 0x3a, 0x15, 0xee, 0x6c, 0x55, 0xd2, 0x46, - 0x89, 0x20, 0xee, 0x7a, 0x4b, 0xfb, 0x70, 0xcb, 0x60, 0x93, 0xc4, 0x69, 0x8d, 0x3b, 0x5b, 0x15, - 0xfe, 0x1a, 0x8d, 0xbc, 0x88, 0xf3, 0xd8, 0xcd, 0xaf, 0x48, 0x46, 0x5d, 0x9f, 0x2f, 0x12, 0xa1, - 0x0d, 0xe0, 0x8b, 0x83, 0xb2, 0x30, 0x54, 0x20, 0x2f, 0x24, 0x97, 0x3b, 0x83, 0xa6, 0x98, 0x49, - 0x1d, 0xb6, 0x90, 0x3a, 0xe7, 0x5c, 0xb0, 0xac, 0x4a, 0x38, 0x04, 0xdb, 0x7e, 0x59, 0x18, 0xa8, - 0x82, 0x21, 0xde, 0xc6, 0x1a, 0x33, 0x34, 0xa2, 0x8c, 0x86, 0x3e, 0x11, 0x4c, 0x7e, 0x2b, 0x5a, - 0xc4, 0x49, 0xae, 0x8d, 0x26, 0xaf, 0xa6, 0xea, 0x91, 0x66, 0xd6, 0x33, 0x66, 0x9e, 0xac, 0x14, - 0x33, 0x10, 0xd8, 0x7a, 0x59, 0x18, 0x63, 0xba, 0x0d, 0xe6, 0x9f, 0xf1, 0x38, 0x94, 0x06, 0xf1, - 0xbb, 0x33, 0x7c, 0xca, 0xe1, 0x9f, 0x10, 0xce, 0x58, 0x1a, 0x49, 0x50, 0x5e, 0xed, 0x9c, 0xf8, - 0x82, 0x67, 0x1a, 0x86, 0xed, 0x19, 0x65, 0x61, 0xbc, 0xdb, 0x60, 0xbf, 0x05, 0x72, 0xa3, 0xdd, - 0xe8, 0x19, 0x79, 0xf0, 0xa7, 0x82, 0xf0, 0xac, 0xba, 0x7d, 0x46, 0x9b, 0x11, 0x3d, 0x46, 0xa8, - 0x1a, 0xbe, 0x98, 0x09, 0x02, 0x53, 0xaa, 0x1e, 0xbd, 0x35, 0x9b, 0xa7, 0xc3, 0x5c, 0x4b, 0xed, - 0x8e, 0xfc, 0x53, 0xdf, 0x17, 0x72, 0x2e, 0xbc, 0xb5, 0xff, 0x7b, 0xb4, 0xef, 0xaf, 0xba, 0x56, - 0xd3, 0xb1, 0xf3, 0xe2, 0x74, 0x40, 0x23, 0x18, 0x89, 0xfe, 0xda, 0x2b, 0xd9, 0x83, 0xbf, 0x14, - 0xa4, 0x5e, 0x56, 0x33, 0x2c, 0xff, 0x4e, 0x78, 0x86, 0x90, 0x9f, 0x31, 0x38, 0x68, 0x22, 0xea, - 0xcd, 0x7d, 0x58, 0xe3, 0x6e, 0xed, 0xfb, 0x46, 0xe0, 0xf7, 0x68, 0x17, 0xb2, 0xed, 0xc0, 0x15, - 0xfd, 0x7f, 0x36, 0x07, 0x24, 0xf8, 0x74, 0x33, 0x0c, 0x98, 0x5e, 0x81, 0x49, 0xdf, 0x34, 0x3d, - 0x3f, 0xc4, 0x8d, 0x18, 0x70, 0x50, 0xa7, 0x77, 0x0f, 0xba, 0x72, 0xff, 0xa0, 0x2b, 0xff, 0x3e, - 0xe8, 0xca, 0xed, 0xa3, 0xde, 0xba, 0x7f, 0xd4, 0x5b, 0x7f, 0x3f, 0xea, 0xad, 0x5f, 0x3e, 0xdd, - 0x7c, 0x4d, 0x33, 0x32, 0x27, 0x09, 0xa9, 0x9e, 0x63, 0xeb, 0xf9, 0x4b, 0xee, 0xed, 0x41, 0xc2, - 0x2f, 0xfe, 0x0b, 0x00, 0x00, 0xff, 0xff, 0x68, 0x4a, 0xe1, 0x10, 0xe6, 0x05, 0x00, 0x00, -} - -func (m *BlockMeta) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *BlockMeta) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *BlockMeta) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.ReplicationFactor != 0 { - i = encodeVarintV1(dAtA, i, uint64(m.ReplicationFactor)) - i-- - dAtA[i] = 0x1 - i-- - dAtA[i] = 0x90 - } - if len(m.DedicatedColumns) > 0 { - for iNdEx := len(m.DedicatedColumns) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.DedicatedColumns[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintV1(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1 - i-- - dAtA[i] = 0x8a - } - } - if m.FooterSize != 0 { - i = encodeVarintV1(dAtA, i, uint64(m.FooterSize)) - i-- - dAtA[i] = 0x1 - i-- - dAtA[i] = 0x80 - } - if m.BloomShardCount != 0 { - i = encodeVarintV1(dAtA, i, uint64(m.BloomShardCount)) - i-- - dAtA[i] = 0x78 - } - if len(m.DataEncoding) > 0 { - i -= len(m.DataEncoding) - copy(dAtA[i:], m.DataEncoding) - i = encodeVarintV1(dAtA, i, uint64(len(m.DataEncoding))) - i-- - dAtA[i] = 0x72 - } - if m.TotalRecords != 0 { - i = encodeVarintV1(dAtA, i, uint64(m.TotalRecords)) - i-- - dAtA[i] = 0x68 - } - if m.IndexPageSize != 0 { - i = encodeVarintV1(dAtA, i, uint64(m.IndexPageSize)) - i-- - dAtA[i] = 0x60 - } - if m.Encoding != 0 { - i = encodeVarintV1(dAtA, i, uint64(m.Encoding)) - i-- - dAtA[i] = 0x58 - } - if m.CompactionLevel != 0 { - i = encodeVarintV1(dAtA, i, uint64(m.CompactionLevel)) - i-- - dAtA[i] = 0x50 - } - if m.Size_ != 0 { - i = encodeVarintV1(dAtA, i, uint64(m.Size_)) - i-- - dAtA[i] = 0x48 - } - if m.TotalObjects != 0 { - i = encodeVarintV1(dAtA, i, uint64(m.TotalObjects)) - i-- - dAtA[i] = 0x40 - } - n1, err1 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.EndTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.EndTime):]) - if err1 != nil { - return 0, err1 - } - i -= n1 - i = encodeVarintV1(dAtA, i, uint64(n1)) - i-- - dAtA[i] = 0x3a - n2, err2 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.StartTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.StartTime):]) - if err2 != nil { - return 0, err2 - } - i -= n2 - i = encodeVarintV1(dAtA, i, uint64(n2)) - i-- - dAtA[i] = 0x32 - if len(m.TenantId) > 0 { - i -= len(m.TenantId) - copy(dAtA[i:], m.TenantId) - i = encodeVarintV1(dAtA, i, uint64(len(m.TenantId))) - i-- - dAtA[i] = 0x2a - } - if len(m.BlockId) > 0 { - i -= len(m.BlockId) - copy(dAtA[i:], m.BlockId) - i = encodeVarintV1(dAtA, i, uint64(len(m.BlockId))) - i-- - dAtA[i] = 0x12 - } - if len(m.Version) > 0 { - i -= len(m.Version) - copy(dAtA[i:], m.Version) - i = encodeVarintV1(dAtA, i, uint64(len(m.Version))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *CompactedBlockMeta) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *CompactedBlockMeta) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *CompactedBlockMeta) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - n3, err3 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CompactedTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.CompactedTime):]) - if err3 != nil { - return 0, err3 - } - i -= n3 - i = encodeVarintV1(dAtA, i, uint64(n3)) - i-- - dAtA[i] = 0x12 - { - size, err := m.BlockMeta.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintV1(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil -} - -func (m *TenantIndex) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *TenantIndex) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *TenantIndex) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.CompactedMeta) > 0 { - for iNdEx := len(m.CompactedMeta) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.CompactedMeta[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintV1(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - } - } - if len(m.Meta) > 0 { - for iNdEx := len(m.Meta) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Meta[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintV1(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - } - n5, err5 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt):]) - if err5 != nil { - return 0, err5 - } - i -= n5 - i = encodeVarintV1(dAtA, i, uint64(n5)) - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil -} - -func encodeVarintV1(dAtA []byte, offset int, v uint64) int { - offset -= sovV1(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *BlockMeta) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Version) - if l > 0 { - n += 1 + l + sovV1(uint64(l)) - } - l = len(m.BlockId) - if l > 0 { - n += 1 + l + sovV1(uint64(l)) - } - l = len(m.TenantId) - if l > 0 { - n += 1 + l + sovV1(uint64(l)) - } - l = github_com_gogo_protobuf_types.SizeOfStdTime(m.StartTime) - n += 1 + l + sovV1(uint64(l)) - l = github_com_gogo_protobuf_types.SizeOfStdTime(m.EndTime) - n += 1 + l + sovV1(uint64(l)) - if m.TotalObjects != 0 { - n += 1 + sovV1(uint64(m.TotalObjects)) - } - if m.Size_ != 0 { - n += 1 + sovV1(uint64(m.Size_)) - } - if m.CompactionLevel != 0 { - n += 1 + sovV1(uint64(m.CompactionLevel)) - } - if m.Encoding != 0 { - n += 1 + sovV1(uint64(m.Encoding)) - } - if m.IndexPageSize != 0 { - n += 1 + sovV1(uint64(m.IndexPageSize)) - } - if m.TotalRecords != 0 { - n += 1 + sovV1(uint64(m.TotalRecords)) - } - l = len(m.DataEncoding) - if l > 0 { - n += 1 + l + sovV1(uint64(l)) - } - if m.BloomShardCount != 0 { - n += 1 + sovV1(uint64(m.BloomShardCount)) - } - if m.FooterSize != 0 { - n += 2 + sovV1(uint64(m.FooterSize)) - } - if len(m.DedicatedColumns) > 0 { - for _, e := range m.DedicatedColumns { - l = e.Size() - n += 2 + l + sovV1(uint64(l)) - } - } - if m.ReplicationFactor != 0 { - n += 2 + sovV1(uint64(m.ReplicationFactor)) - } - return n -} - -func (m *CompactedBlockMeta) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = m.BlockMeta.Size() - n += 1 + l + sovV1(uint64(l)) - l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CompactedTime) - n += 1 + l + sovV1(uint64(l)) - return n -} - -func (m *TenantIndex) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt) - n += 1 + l + sovV1(uint64(l)) - if len(m.Meta) > 0 { - for _, e := range m.Meta { - l = e.Size() - n += 1 + l + sovV1(uint64(l)) - } - } - if len(m.CompactedMeta) > 0 { - for _, e := range m.CompactedMeta { - l = e.Size() - n += 1 + l + sovV1(uint64(l)) - } - } - return n -} - -func sovV1(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozV1(x uint64) (n int) { - return sovV1(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *BlockMeta) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowV1 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: BlockMeta: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: BlockMeta: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowV1 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthV1 - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthV1 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Version = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field BlockId", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowV1 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthV1 - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthV1 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.BlockId = append(m.BlockId[:0], dAtA[iNdEx:postIndex]...) - if m.BlockId == nil { - m.BlockId = []byte{} - } - iNdEx = postIndex - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field TenantId", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowV1 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthV1 - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthV1 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.TenantId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 6: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field StartTime", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowV1 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthV1 - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthV1 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.StartTime, dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 7: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field EndTime", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowV1 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthV1 - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthV1 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.EndTime, dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 8: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TotalObjects", wireType) - } - m.TotalObjects = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowV1 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.TotalObjects |= int32(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 9: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Size_", wireType) - } - m.Size_ = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowV1 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Size_ |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 10: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field CompactionLevel", wireType) - } - m.CompactionLevel = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowV1 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.CompactionLevel |= uint32(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 11: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Encoding", wireType) - } - m.Encoding = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowV1 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Encoding |= uint32(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 12: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field IndexPageSize", wireType) - } - m.IndexPageSize = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowV1 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.IndexPageSize |= uint32(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 13: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TotalRecords", wireType) - } - m.TotalRecords = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowV1 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.TotalRecords |= uint32(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 14: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DataEncoding", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowV1 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthV1 - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthV1 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.DataEncoding = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 15: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field BloomShardCount", wireType) - } - m.BloomShardCount = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowV1 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.BloomShardCount |= uint32(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 16: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field FooterSize", wireType) - } - m.FooterSize = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowV1 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.FooterSize |= uint32(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 17: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DedicatedColumns", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowV1 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthV1 - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthV1 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.DedicatedColumns = append(m.DedicatedColumns, &tempopb.DedicatedColumn{}) - if err := m.DedicatedColumns[len(m.DedicatedColumns)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 18: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ReplicationFactor", wireType) - } - m.ReplicationFactor = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowV1 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.ReplicationFactor |= uint32(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipV1(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthV1 - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *CompactedBlockMeta) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowV1 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: CompactedBlockMeta: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: CompactedBlockMeta: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field BlockMeta", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowV1 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthV1 - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthV1 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.BlockMeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CompactedTime", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowV1 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthV1 - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthV1 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.CompactedTime, dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipV1(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthV1 - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *TenantIndex) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowV1 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: TenantIndex: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: TenantIndex: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CreatedAt", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowV1 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthV1 - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthV1 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Meta", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowV1 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthV1 - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthV1 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Meta = append(m.Meta, &BlockMeta{}) - if err := m.Meta[len(m.Meta)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CompactedMeta", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowV1 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthV1 - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthV1 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.CompactedMeta = append(m.CompactedMeta, &CompactedBlockMeta{}) - if err := m.CompactedMeta[len(m.CompactedMeta)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipV1(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthV1 - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipV1(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowV1 - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowV1 - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowV1 - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthV1 - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupV1 - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthV1 - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthV1 = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowV1 = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupV1 = fmt.Errorf("proto: unexpected end of group") -) diff --git a/tempodb/backend/v1/v1.proto b/tempodb/backend/v1/v1.proto index 805af379917..72d187e0da0 100644 --- a/tempodb/backend/v1/v1.proto +++ b/tempodb/backend/v1/v1.proto @@ -2,18 +2,20 @@ syntax = "proto3"; package backend.v1; -import "pkg/tempopb/tempo.proto"; +// import "pkg/tempopb/tempo.proto"; import "google/protobuf/timestamp.proto"; import "github.com/gogo/protobuf/gogoproto/gogo.proto"; +// option go_package = "github.com/grafana/tempo/tempodb/backend/v1"; +option go_package = "tempodb/backend"; -option go_package = "github.com/grafana/tempo/tempodb/backend/v1"; +option (gogoproto.marshaler_all) = true; message BlockMeta { string version = 1[(gogoproto.jsontag) = "format"]; - bytes block_id = 2[(gogoproto.jsontag) = "blockID"]; - string tenant_id = 5[(gogoproto.jsontag) = "tenantID"]; + bytes block_id = 2[(gogoproto.jsontag) = "blockID", (gogoproto.customname) = "BlockID"]; + string tenant_id = 5[(gogoproto.jsontag) = "tenantID", (gogoproto.customname) = "TenantID"]; google.protobuf.Timestamp start_time = 6[(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = "startTime"]; google.protobuf.Timestamp end_time = 7[(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = "endTime"]; int32 total_objects = 8[(gogoproto.jsontag) = "totalObjects"]; @@ -25,7 +27,11 @@ message BlockMeta { string data_encoding = 14[(gogoproto.jsontag) = "dataEncoding"]; uint32 bloom_shard_count = 15[(gogoproto.jsontag) = "bloomShards"]; uint32 footer_size = 16[(gogoproto.jsontag) = "footerSize"]; - repeated tempopb.DedicatedColumn dedicated_columns = 17[(gogoproto.jsontag) = "dedicatedColumns,omitempty"]; + // repeated bytes dedicated_columns = 17 [(gogoproto.customtype) = "github.com/grafana/tempo/pkg/tempopb.DedicatedColumn"]; + // repeated bytes dedicated_columns = 17 [(gogoproto.customtype) = "github.com/grafana/tempo/tempodb/backend/meta.DedicatedColumn"]; + bytes dedicated_columns = 17 [(gogoproto.customtype) = "DedicatedColumns", (gogoproto.jsontag) = "dedicatedColumns,omitempty", (gogoproto.nullable) = false]; + // bytes dedicated_columns = 17; + // repeated tempopb.DedicatedColumn dedicated_columns = 17[(gogoproto.jsontag) = "dedicatedColumns,omitempty"]; uint32 replication_factor = 18[(gogoproto.jsontag) = "replicationFactor,omitempty"]; } From 05f159f1ca4aed3d3b684ccaee1c4f6f41dff44b Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Tue, 10 Sep 2024 19:51:52 +0000 Subject: [PATCH 05/71] Add wrapper around google UUID for proto marshaling --- pkg/uuid/uuid.go | 31 +++++++++++++++++++++++++++++++ pkg/uuid/uuid_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 pkg/uuid/uuid.go create mode 100644 pkg/uuid/uuid_test.go diff --git a/pkg/uuid/uuid.go b/pkg/uuid/uuid.go new file mode 100644 index 00000000000..ab2a9e9b3f6 --- /dev/null +++ b/pkg/uuid/uuid.go @@ -0,0 +1,31 @@ +package uuid + +import ( + google_uuid "github.com/google/uuid" +) + +type UUID struct { + google_uuid.UUID +} + +func (u *UUID) Size() int { + return 16 +} + +func (u *UUID) MarshalTo(data []byte) (n int, err error) { + b, err := u.UUID.MarshalBinary() + if err != nil { + return 0, err + } + + return copy(data, b), nil +} + +func (u *UUID) Unmarshal(data []byte) error { + err := u.UUID.UnmarshalBinary(data) + if err != nil { + return err + } + + return nil +} diff --git a/pkg/uuid/uuid_test.go b/pkg/uuid/uuid_test.go new file mode 100644 index 00000000000..322d9eecfc0 --- /dev/null +++ b/pkg/uuid/uuid_test.go @@ -0,0 +1,28 @@ +package uuid + +import ( + "testing" + + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func Test_roundTrip(t *testing.T) { + u := UUID{uuid.New()} + t.Logf("u %x", u) + + require.Equal(t, 16, u.Size()) + + b := make([]byte, 16) + l, err := u.MarshalTo(b) + require.NoError(t, err) + require.Equal(t, 16, l) + require.Equal(t, 16, len(b)) + + u2 := UUID{} + err = u2.Unmarshal(b) + t.Logf("u2 %x", u2) + require.NoError(t, err) + assert.Equal(t, u.UUID, u2.UUID) +} From c3b14fb173fcccaa8a899868ae088fb8cf7f7ace Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Tue, 10 Sep 2024 19:52:19 +0000 Subject: [PATCH 06/71] Update blocklist for wrapper type --- tempodb/blocklist/list.go | 47 ++---- tempodb/blocklist/list_test.go | 155 ++++++++++---------- tempodb/blocklist/poller.go | 26 ++-- tempodb/blocklist/poller_test.go | 243 ++++++++++++++----------------- 4 files changed, 210 insertions(+), 261 deletions(-) diff --git a/tempodb/blocklist/list.go b/tempodb/blocklist/list.go index 16b405d7491..073a0511161 100644 --- a/tempodb/blocklist/list.go +++ b/tempodb/blocklist/list.go @@ -1,7 +1,6 @@ package blocklist import ( - "bytes" "sync" "github.com/google/uuid" @@ -132,12 +131,8 @@ func (l *List) updateInternal(tenantID string, add []*backend.BlockMeta, remove matchedRemovals := make(map[uuid.UUID]struct{}) for _, b := range blocklist { for _, rem := range remove { - if bytes.Equal(b.BlockID, rem.BlockID) { - id, err := uuid.ParseBytes(b.BlockID) - if err != nil { - // FIXME - } - matchedRemovals[id] = struct{}{} + if b.BlockID.UUID == rem.BlockID.UUID { + matchedRemovals[rem.BlockID.UUID] = struct{}{} break } } @@ -145,26 +140,16 @@ func (l *List) updateInternal(tenantID string, add []*backend.BlockMeta, remove existingMetas := make(map[uuid.UUID]struct{}) newblocklist := make([]*backend.BlockMeta, 0, len(blocklist)-len(matchedRemovals)+len(add)) - // var id uuid.UUID - // var err error // rebuild the blocklist dropping all removals for _, b := range blocklist { - id, err := uuid.ParseBytes(b.BlockID) - if err != nil { - // FIXME: - } - existingMetas[id] = struct{}{} - if _, ok := matchedRemovals[id]; !ok { + existingMetas[b.BlockID.UUID] = struct{}{} + if _, ok := matchedRemovals[b.BlockID.UUID]; !ok { newblocklist = append(newblocklist, b) } } // add new blocks (only if they don't already exist) for _, b := range add { - id, err := uuid.ParseBytes(b.BlockID) - if err != nil { - // FIXME: - } - if _, ok := existingMetas[id]; !ok { + if _, ok := existingMetas[b.BlockID.UUID]; !ok { newblocklist = append(newblocklist, b) } } @@ -177,12 +162,8 @@ func (l *List) updateInternal(tenantID string, add []*backend.BlockMeta, remove compactedRemovals := map[uuid.UUID]struct{}{} for _, c := range compactedBlocklist { for _, rem := range compactedRemove { - id, err := uuid.ParseBytes(c.BlockID) - if err != nil { - // FIXME: - } - if bytes.Equal(c.BlockID, rem.BlockID) { - compactedRemovals[id] = struct{}{} + if c.BlockID.UUID == rem.BlockID.UUID { + compactedRemovals[rem.BlockID.UUID] = struct{}{} break } } @@ -192,21 +173,13 @@ func (l *List) updateInternal(tenantID string, add []*backend.BlockMeta, remove newCompactedBlocklist := make([]*backend.CompactedBlockMeta, 0, len(compactedBlocklist)-len(compactedRemovals)+len(compactedAdd)) // rebuild the blocklist dropping all removals for _, b := range compactedBlocklist { - id, err := uuid.ParseBytes(b.BlockID) - if err != nil { - // FIXME: - } - existingMetas[id] = struct{}{} - if _, ok := compactedRemovals[id]; !ok { + existingMetas[b.BlockID.UUID] = struct{}{} + if _, ok := compactedRemovals[b.BlockID.UUID]; !ok { newCompactedBlocklist = append(newCompactedBlocklist, b) } } for _, b := range compactedAdd { - id, err := uuid.ParseBytes(b.BlockID) - if err != nil { - // FIXME: - } - if _, ok := existingMetas[id]; !ok { + if _, ok := existingMetas[b.BlockID.UUID]; !ok { newCompactedBlocklist = append(newCompactedBlocklist, b) } } diff --git a/tempodb/blocklist/list_test.go b/tempodb/blocklist/list_test.go index c1976986d0f..9793fed56f7 100644 --- a/tempodb/blocklist/list_test.go +++ b/tempodb/blocklist/list_test.go @@ -4,10 +4,11 @@ import ( "sort" "testing" - "github.com/google/uuid" + google_uuid "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" ) @@ -29,12 +30,12 @@ func TestApplyPollResults(t *testing.T) { metas: PerTenant{ "test": []*backend.BlockMeta{ { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, }, "test2": []*backend.BlockMeta{ { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, }, }, @@ -46,19 +47,19 @@ func TestApplyPollResults(t *testing.T) { "test": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, }, }, "test2": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, }, { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, }, }, }, @@ -70,12 +71,12 @@ func TestApplyPollResults(t *testing.T) { metas: PerTenant{ "test": []*backend.BlockMeta{ { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, }, "blerg": []*backend.BlockMeta{ { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, }, }, @@ -83,19 +84,19 @@ func TestApplyPollResults(t *testing.T) { "test": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, }, }, "test2": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, }, { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, }, }, }, @@ -144,13 +145,13 @@ func TestUpdate(t *testing.T) { existing: nil, add: []*backend.BlockMeta{ { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, }, remove: nil, expected: []*backend.BlockMeta{ { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, }, }, @@ -158,21 +159,21 @@ func TestUpdate(t *testing.T) { name: "add to existing", existing: []*backend.BlockMeta{ { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, }, add: []*backend.BlockMeta{ { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, }, }, remove: nil, expected: []*backend.BlockMeta{ { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, }, }, }, @@ -182,7 +183,7 @@ func TestUpdate(t *testing.T) { add: nil, remove: []*backend.BlockMeta{ { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, }, }, expected: nil, @@ -191,14 +192,14 @@ func TestUpdate(t *testing.T) { name: "remove nil", existing: []*backend.BlockMeta{ { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, }, }, add: nil, remove: nil, expected: []*backend.BlockMeta{ { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, }, }, }, @@ -206,21 +207,21 @@ func TestUpdate(t *testing.T) { name: "remove existing", existing: []*backend.BlockMeta{ { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, }, }, add: nil, remove: []*backend.BlockMeta{ { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, }, expected: []*backend.BlockMeta{ { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, }, }, }, @@ -228,18 +229,18 @@ func TestUpdate(t *testing.T) { name: "remove no match", existing: []*backend.BlockMeta{ { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, }, add: nil, remove: []*backend.BlockMeta{ { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, }, }, expected: []*backend.BlockMeta{ { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, }, }, @@ -247,28 +248,28 @@ func TestUpdate(t *testing.T) { name: "add and remove", existing: []*backend.BlockMeta{ { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, }, }, add: []*backend.BlockMeta{ { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000003")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, }, }, remove: []*backend.BlockMeta{ { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, }, }, expected: []*backend.BlockMeta{ { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000003")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, }, }, }, @@ -276,24 +277,24 @@ func TestUpdate(t *testing.T) { name: "add already exists", existing: []*backend.BlockMeta{ { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, }, add: []*backend.BlockMeta{ { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, }, }, remove: nil, expected: []*backend.BlockMeta{ { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, { - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, }, }, }, @@ -335,14 +336,14 @@ func TestUpdateCompacted(t *testing.T) { add: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, }, }, expected: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, }, }, @@ -352,26 +353,26 @@ func TestUpdateCompacted(t *testing.T) { existing: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, }, }, add: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, }, }, }, expected: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, }, { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, }, }, }, @@ -381,31 +382,31 @@ func TestUpdateCompacted(t *testing.T) { existing: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, }, }, add: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, }, { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, }, }, }, expected: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, }, { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, }, }, }, @@ -415,38 +416,38 @@ func TestUpdateCompacted(t *testing.T) { existing: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, }, { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, }, }, }, add: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000003")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, }, }, }, remove: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000002")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, }, }, }, expected: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, }, }, { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000003")), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, }, }, }, @@ -473,10 +474,10 @@ func TestUpdatesSaved(t *testing.T) { // unlike most tests these are applied serially to the same list object and the expected // results are cumulative across all tests - one := uuid.MustParse("00000000-0000-0000-0000-000000000001") - two := uuid.MustParse("00000000-0000-0000-0000-000000000002") - oneOhOne := uuid.MustParse("10000000-0000-0000-0000-000000000001") - oneOhTwo := uuid.MustParse("10000000-0000-0000-0000-000000000002") + one := google_uuid.MustParse("00000000-0000-0000-0000-000000000001") + two := google_uuid.MustParse("00000000-0000-0000-0000-000000000002") + oneOhOne := google_uuid.MustParse("10000000-0000-0000-0000-000000000001") + oneOhTwo := google_uuid.MustParse("10000000-0000-0000-0000-000000000002") tests := []struct { applyMetas PerTenant @@ -495,7 +496,7 @@ func TestUpdatesSaved(t *testing.T) { applyMetas: PerTenant{ "test": []*backend.BlockMeta{ { - BlockID: uuidBytes(one), + BlockID: uuid.UUID{UUID: one}, }, }, }, @@ -503,7 +504,7 @@ func TestUpdatesSaved(t *testing.T) { "test": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(oneOhOne), + BlockID: uuid.UUID{UUID: oneOhOne}, }, }, }, @@ -511,21 +512,21 @@ func TestUpdatesSaved(t *testing.T) { updateTenant: "test", addMetas: []*backend.BlockMeta{ { - BlockID: uuidBytes(one), + BlockID: uuid.UUID{UUID: one}, }, { - BlockID: uuidBytes(two), + BlockID: uuid.UUID{UUID: two}, }, }, removeMetas: []*backend.BlockMeta{ { - BlockID: uuidBytes(one), + BlockID: uuid.UUID{UUID: one}, }, }, addCompacted: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(oneOhTwo), + BlockID: uuid.UUID{UUID: oneOhTwo}, }, }, }, @@ -533,7 +534,7 @@ func TestUpdatesSaved(t *testing.T) { expectedMetas: PerTenant{ "test": []*backend.BlockMeta{ { - BlockID: uuidBytes(two), + BlockID: uuid.UUID{UUID: two}, }, }, }, @@ -541,12 +542,12 @@ func TestUpdatesSaved(t *testing.T) { "test": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(oneOhOne), + BlockID: uuid.UUID{UUID: oneOhOne}, }, }, { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(oneOhTwo), + BlockID: uuid.UUID{UUID: oneOhTwo}, }, }, }, @@ -557,7 +558,7 @@ func TestUpdatesSaved(t *testing.T) { applyMetas: PerTenant{ "test": []*backend.BlockMeta{ { - BlockID: uuidBytes(one), + BlockID: uuid.UUID{UUID: one}, }, }, }, @@ -565,7 +566,7 @@ func TestUpdatesSaved(t *testing.T) { "test": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(oneOhOne), + BlockID: uuid.UUID{UUID: oneOhOne}, }, }, }, @@ -578,7 +579,7 @@ func TestUpdatesSaved(t *testing.T) { // BlockID: one, // }, { - BlockID: uuidBytes(two), + BlockID: uuid.UUID{UUID: two}, }, }, }, @@ -586,12 +587,12 @@ func TestUpdatesSaved(t *testing.T) { "test": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(oneOhOne), + BlockID: uuid.UUID{UUID: oneOhOne}, }, }, { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(oneOhTwo), + BlockID: uuid.UUID{UUID: oneOhTwo}, }, }, }, @@ -602,7 +603,7 @@ func TestUpdatesSaved(t *testing.T) { applyMetas: PerTenant{ "test": []*backend.BlockMeta{ { - BlockID: uuidBytes(one), + BlockID: uuid.UUID{UUID: one}, }, }, }, @@ -610,7 +611,7 @@ func TestUpdatesSaved(t *testing.T) { "test": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(oneOhOne), + BlockID: uuid.UUID{UUID: oneOhOne}, }, }, }, @@ -619,7 +620,7 @@ func TestUpdatesSaved(t *testing.T) { expectedMetas: PerTenant{ "test": []*backend.BlockMeta{ { - BlockID: uuidBytes(one), + BlockID: uuid.UUID{UUID: one}, }, }, }, @@ -627,7 +628,7 @@ func TestUpdatesSaved(t *testing.T) { "test": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(oneOhOne), + BlockID: uuid.UUID{UUID: oneOhOne}, }, }, }, diff --git a/tempodb/blocklist/poller.go b/tempodb/blocklist/poller.go index 342a0438847..ead5e9aa14b 100644 --- a/tempodb/blocklist/poller.go +++ b/tempodb/blocklist/poller.go @@ -13,7 +13,7 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" - "github.com/google/uuid" + google_uuid "github.com/google/uuid" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "go.opentelemetry.io/otel" @@ -320,30 +320,22 @@ func (p *Poller) pollTenantBlocks( var ( metas = previous.Metas(tenantID) compactedMetas = previous.CompactedMetas(tenantID) - mm = make(map[uuid.UUID]*backend.BlockMeta, len(metas)) - cm = make(map[uuid.UUID]*backend.CompactedBlockMeta, len(compactedMetas)) + mm = make(map[google_uuid.UUID]*backend.BlockMeta, len(metas)) + cm = make(map[google_uuid.UUID]*backend.CompactedBlockMeta, len(compactedMetas)) newBlockList = make([]*backend.BlockMeta, 0, len(currentBlockIDs)) newCompactedBlocklist = make([]*backend.CompactedBlockMeta, 0, len(currentCompactedBlockIDs)) - unknownBlockIDs = make(map[uuid.UUID]bool, 1000) + unknownBlockIDs = make(map[google_uuid.UUID]bool, 1000) ) span.SetAttributes(attribute.Int("metas", len(metas))) span.SetAttributes(attribute.Int("compactedMetas", len(compactedMetas))) for _, i := range metas { - id, err := uuid.ParseBytes(i.BlockID) - if err != nil { - return nil, nil, fmt.Errorf("failed parsing meta UUID bytes: %w", err) - } - mm[id] = i + mm[i.BlockID.UUID] = i } for _, i := range compactedMetas { - id, err := uuid.ParseBytes(i.BlockID) - if err != nil { - return nil, nil, fmt.Errorf("failed parsing compacted meta UUID bytes: %w", err) - } - cm[id] = i + cm[i.BlockID.UUID] = i } // The boolean here to track if we know the block has been compacted @@ -393,7 +385,7 @@ func (p *Poller) pollTenantBlocks( func (p *Poller) pollUnknown( ctx context.Context, - unknownBlocks map[uuid.UUID]bool, + unknownBlocks map[google_uuid.UUID]bool, tenantID string, ) ([]*backend.BlockMeta, []*backend.CompactedBlockMeta, error) { derivedCtx, span := tracer.Start(ctx, "pollUnknown", trace.WithAttributes( @@ -420,7 +412,7 @@ func (p *Poller) pollUnknown( mtx.Unlock() bg.Add(1) - go func(id uuid.UUID, compacted bool) { + go func(id google_uuid.UUID, compacted bool) { defer bg.Done() if p.cfg.PollJitterMs > 0 { @@ -463,7 +455,7 @@ func (p *Poller) pollUnknown( func (p *Poller) pollBlock( ctx context.Context, tenantID string, - blockID uuid.UUID, + blockID google_uuid.UUID, compacted bool, ) (*backend.BlockMeta, *backend.CompactedBlockMeta, error) { derivedCtx, span := tracer.Start(ctx, "Poller.pollBlock") diff --git a/tempodb/blocklist/poller_test.go b/tempodb/blocklist/poller_test.go index 41f01e42996..b40ca2d86f3 100644 --- a/tempodb/blocklist/poller_test.go +++ b/tempodb/blocklist/poller_test.go @@ -14,10 +14,11 @@ import ( "time" "github.com/go-kit/log" - "github.com/google/uuid" + google_uuid "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" ) @@ -37,9 +38,9 @@ func (m *mockJobSharder) Owns(_ string) bool { return m.owns } func TestTenantIndexBuilder(t *testing.T) { var ( - one = uuid.MustParse("00000000-0000-0000-0000-000000000001") - two = uuid.MustParse("00000000-0000-0000-0000-000000000002") - three = uuid.MustParse("00000000-0000-0000-0000-000000000003") + one = uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")} + two = uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")} + three = uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")} ) tests := []struct { @@ -60,7 +61,7 @@ func TestTenantIndexBuilder(t *testing.T) { list: PerTenant{ "test": []*backend.BlockMeta{ { - BlockID: []byte(one.String()), + BlockID: one, }, }, }, @@ -71,14 +72,14 @@ func TestTenantIndexBuilder(t *testing.T) { list: PerTenant{ "test": []*backend.BlockMeta{ { - BlockID: []byte(one.String()), + BlockID: one, }, }, }, expectedList: PerTenant{ "test": []*backend.BlockMeta{ { - BlockID: []byte(one.String()), + BlockID: one, }, }, }, @@ -92,7 +93,7 @@ func TestTenantIndexBuilder(t *testing.T) { "test": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: []byte(one.String()), + BlockID: one, }, }, }, @@ -104,7 +105,7 @@ func TestTenantIndexBuilder(t *testing.T) { "test": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: []byte(one.String()), + BlockID: one, }, }, }, @@ -115,12 +116,12 @@ func TestTenantIndexBuilder(t *testing.T) { list: PerTenant{ "test2": []*backend.BlockMeta{ { - BlockID: []byte(three.String()), + BlockID: three, }, }, "test": []*backend.BlockMeta{ { - BlockID: []byte(two.String()), + BlockID: two, }, }, }, @@ -128,7 +129,7 @@ func TestTenantIndexBuilder(t *testing.T) { "test": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: []byte(one.String()), + BlockID: one, }, }, }, @@ -136,12 +137,12 @@ func TestTenantIndexBuilder(t *testing.T) { expectedList: PerTenant{ "test2": []*backend.BlockMeta{ { - BlockID: []byte(three.String()), + BlockID: three, }, }, "test": []*backend.BlockMeta{ { - BlockID: []byte(two.String()), + BlockID: two, }, }, }, @@ -149,7 +150,7 @@ func TestTenantIndexBuilder(t *testing.T) { "test": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: []byte(one.String()), + BlockID: one, }, }, }, @@ -289,7 +290,7 @@ func TestTenantIndexFallback(t *testing.T) { } func TestPollBlock(t *testing.T) { - one := uuid.MustParse("00000000-0000-0000-0000-000000000001") + one := uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")} tests := []struct { name string @@ -313,42 +314,42 @@ func TestPollBlock(t *testing.T) { list: PerTenant{ "test": []*backend.BlockMeta{ { - BlockID: uuidBytes(one), + BlockID: one, }, }, }, expectedMeta: &backend.BlockMeta{ - BlockID: uuidBytes(one), + BlockID: one, }, }, { name: "compactedblock exists", pollTenantID: "test", - pollBlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + pollBlockID: one, compactedList: PerTenantCompacted{ "test": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: one, }, }, }, }, expectedCompactedMeta: &backend.CompactedBlockMeta{ BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: one, }, }, }, { name: "errors", pollTenantID: "test", - pollBlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + pollBlockID: one, compactedList: PerTenantCompacted{ "test": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuidBytes(uuid.MustParse("00000000-0000-0000-0000-000000000001")), + BlockID: one, }, }, }, @@ -369,7 +370,7 @@ func TestPollBlock(t *testing.T) { PollFallback: testPollFallback, TenantIndexBuilders: testBuilders, }, &mockJobSharder{}, r, c, w, log.NewNopLogger()) - actualMeta, actualCompactedMeta, err := poller.pollBlock(context.Background(), tc.pollTenantID, tc.pollBlockID, false) + actualMeta, actualCompactedMeta, err := poller.pollBlock(context.Background(), tc.pollTenantID, tc.pollBlockID.UUID, false) assert.Equal(t, tc.expectedMeta, actualMeta) assert.Equal(t, tc.expectedCompactedMeta, actualCompactedMeta) @@ -606,7 +607,7 @@ func TestPollTolerateConsecutiveErrors(t *testing.T) { // This mock reader returns error or nil based on the tenant ID r := &backend.MockReader{ - BlocksFn: func(_ context.Context, tenantID string) ([]uuid.UUID, []uuid.UUID, error) { + BlocksFn: func(_ context.Context, tenantID string) ([]google_uuid.UUID, []google_uuid.UUID, error) { mtx.Lock() defer func() { callCounter[tenantID]++ @@ -658,9 +659,9 @@ func TestPollTolerateConsecutiveErrors(t *testing.T) { } func TestPollComparePreviousResults(t *testing.T) { - zero := uuid.MustParse("00000000-0000-0000-0000-000000000000") - aaa := uuid.MustParse("00000000-0000-0000-0000-00000000000A") - eff := uuid.MustParse("00000000-0000-0000-0000-00000000000F") + zero := uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")} + aaa := uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-00000000000A")} + eff := uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-00000000000F")} testCases := []struct { name string @@ -674,8 +675,8 @@ func TestPollComparePreviousResults(t *testing.T) { expectedPerTenant PerTenant expectedCompactedPerTenant PerTenantCompacted - expectedBlockMetaCalls map[string]map[uuid.UUID]int - expectedCompactedBlockMetaCalls map[string]map[uuid.UUID]int + expectedBlockMetaCalls map[string]map[google_uuid.UUID]int + expectedCompactedBlockMetaCalls map[string]map[google_uuid.UUID]int tollerateErrors int tollerateTenantFailures int @@ -689,32 +690,32 @@ func TestPollComparePreviousResults(t *testing.T) { previousCompactedPerTenant: PerTenantCompacted{}, currentPerTenant: PerTenant{ "test": []*backend.BlockMeta{ - {BlockID: uuidBytes(zero)}, + {BlockID: zero}, }, }, currentCompactedPerTenant: PerTenantCompacted{ "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(eff)}}, + {BlockMeta: backend.BlockMeta{BlockID: eff}}, }, }, expectedPerTenant: PerTenant{ "test": []*backend.BlockMeta{ - {BlockID: uuidBytes(zero)}, + {BlockID: zero}, }, }, expectedCompactedPerTenant: PerTenantCompacted{ "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(eff)}}, + {BlockMeta: backend.BlockMeta{BlockID: eff}}, }, }, - expectedBlockMetaCalls: map[string]map[uuid.UUID]int{ + expectedBlockMetaCalls: map[string]map[google_uuid.UUID]int{ "test": { - zero: 1, + zero.UUID: 1, }, }, - expectedCompactedBlockMetaCalls: map[string]map[uuid.UUID]int{ + expectedCompactedBlockMetaCalls: map[string]map[google_uuid.UUID]int{ "test": { - eff: 1, + eff.UUID: 1, }, }, }, @@ -722,69 +723,69 @@ func TestPollComparePreviousResults(t *testing.T) { name: "with previous results, meta should be read from only new blocks", previousPerTenant: PerTenant{ "test": []*backend.BlockMeta{ - {BlockID: uuidBytes(zero)}, - {BlockID: uuidBytes(eff)}, + {BlockID: zero}, + {BlockID: eff}, }, }, previousCompactedPerTenant: PerTenantCompacted{}, currentPerTenant: PerTenant{ "test": []*backend.BlockMeta{ - {BlockID: uuidBytes(zero)}, - {BlockID: uuidBytes(eff)}, + {BlockID: zero}, + {BlockID: eff}, }, }, currentCompactedPerTenant: PerTenantCompacted{}, expectedPerTenant: PerTenant{ "test": []*backend.BlockMeta{ - {BlockID: uuidBytes(zero)}, - {BlockID: uuidBytes(eff)}, + {BlockID: zero}, + {BlockID: eff}, }, }, expectedCompactedPerTenant: PerTenantCompacted{ "test": []*backend.CompactedBlockMeta{}, }, - expectedBlockMetaCalls: map[string]map[uuid.UUID]int{}, + expectedBlockMetaCalls: map[string]map[google_uuid.UUID]int{}, }, { name: "with previous results, blocks that have been compacted since the last poll should be known as compacted", previousPerTenant: PerTenant{ "test": []*backend.BlockMeta{ - {BlockID: uuidBytes(zero)}, - {BlockID: uuidBytes(aaa)}, + {BlockID: zero}, + {BlockID: aaa}, }, }, previousCompactedPerTenant: PerTenantCompacted{}, currentPerTenant: PerTenant{ "test": []*backend.BlockMeta{ - {BlockID: uuidBytes(eff)}, + {BlockID: eff}, }, }, currentCompactedPerTenant: PerTenantCompacted{ "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(zero)}}, - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(aaa)}}, + {BlockMeta: backend.BlockMeta{BlockID: zero}}, + {BlockMeta: backend.BlockMeta{BlockID: aaa}}, }, }, expectedPerTenant: PerTenant{ "test": []*backend.BlockMeta{ - {BlockID: uuidBytes(eff)}, + {BlockID: eff}, }, }, expectedCompactedPerTenant: PerTenantCompacted{ "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(aaa)}}, - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(zero)}}, + {BlockMeta: backend.BlockMeta{BlockID: aaa}}, + {BlockMeta: backend.BlockMeta{BlockID: zero}}, }, }, - expectedBlockMetaCalls: map[string]map[uuid.UUID]int{ + expectedBlockMetaCalls: map[string]map[google_uuid.UUID]int{ "test": { - eff: 1, + eff.UUID: 1, }, }, - expectedCompactedBlockMetaCalls: map[string]map[uuid.UUID]int{ + expectedCompactedBlockMetaCalls: map[string]map[google_uuid.UUID]int{ "test": { - aaa: 1, - zero: 1, + aaa.UUID: 1, + zero.UUID: 1, }, }, }, @@ -793,17 +794,17 @@ func TestPollComparePreviousResults(t *testing.T) { previousPerTenant: PerTenant{}, previousCompactedPerTenant: PerTenantCompacted{ "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(zero)}}, - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(aaa)}}, - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(eff)}}, + {BlockMeta: backend.BlockMeta{BlockID: zero}}, + {BlockMeta: backend.BlockMeta{BlockID: aaa}}, + {BlockMeta: backend.BlockMeta{BlockID: eff}}, }, }, currentPerTenant: PerTenant{}, currentCompactedPerTenant: PerTenantCompacted{ "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(zero)}}, - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(aaa)}}, - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(eff)}}, + {BlockMeta: backend.BlockMeta{BlockID: zero}}, + {BlockMeta: backend.BlockMeta{BlockID: aaa}}, + {BlockMeta: backend.BlockMeta{BlockID: eff}}, }, }, expectedPerTenant: PerTenant{ @@ -811,26 +812,26 @@ func TestPollComparePreviousResults(t *testing.T) { }, expectedCompactedPerTenant: PerTenantCompacted{ "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(zero)}}, - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(aaa)}}, - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(eff)}}, + {BlockMeta: backend.BlockMeta{BlockID: zero}}, + {BlockMeta: backend.BlockMeta{BlockID: aaa}}, + {BlockMeta: backend.BlockMeta{BlockID: eff}}, }, }, - expectedBlockMetaCalls: map[string]map[uuid.UUID]int{}, + expectedBlockMetaCalls: map[string]map[google_uuid.UUID]int{}, }, { name: "with previous compactions removed, should be forgotten", previousPerTenant: PerTenant{}, previousCompactedPerTenant: PerTenantCompacted{ "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(zero)}}, + {BlockMeta: backend.BlockMeta{BlockID: zero}}, }, }, currentPerTenant: PerTenant{}, currentCompactedPerTenant: PerTenantCompacted{}, expectedPerTenant: PerTenant{}, expectedCompactedPerTenant: PerTenantCompacted{}, - expectedBlockMetaCalls: map[string]map[uuid.UUID]int{}, + expectedBlockMetaCalls: map[string]map[google_uuid.UUID]int{}, }, { name: "previous results with read error should maintain previous results", @@ -840,17 +841,17 @@ func TestPollComparePreviousResults(t *testing.T) { previousPerTenant: PerTenant{}, previousCompactedPerTenant: PerTenantCompacted{ "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(zero)}}, - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(aaa)}}, - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(eff)}}, + {BlockMeta: backend.BlockMeta{BlockID: zero}}, + {BlockMeta: backend.BlockMeta{BlockID: aaa}}, + {BlockMeta: backend.BlockMeta{BlockID: eff}}, }, }, currentPerTenant: PerTenant{}, currentCompactedPerTenant: PerTenantCompacted{ "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(zero)}}, - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(aaa)}}, - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(eff)}}, + {BlockMeta: backend.BlockMeta{BlockID: zero}}, + {BlockMeta: backend.BlockMeta{BlockID: aaa}}, + {BlockMeta: backend.BlockMeta{BlockID: eff}}, }, }, expectedPerTenant: PerTenant{ @@ -858,12 +859,12 @@ func TestPollComparePreviousResults(t *testing.T) { }, expectedCompactedPerTenant: PerTenantCompacted{ "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(zero)}}, - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(aaa)}}, - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(eff)}}, + {BlockMeta: backend.BlockMeta{BlockID: zero}}, + {BlockMeta: backend.BlockMeta{BlockID: aaa}}, + {BlockMeta: backend.BlockMeta{BlockID: eff}}, }, }, - expectedBlockMetaCalls: map[string]map[uuid.UUID]int{}, + expectedBlockMetaCalls: map[string]map[google_uuid.UUID]int{}, }, { name: "previous results with read error should maintain previous results when tolerations are low and multiple tenants", @@ -872,46 +873,46 @@ func TestPollComparePreviousResults(t *testing.T) { readerErr: true, previousPerTenant: PerTenant{ "test2": []*backend.BlockMeta{ - {BlockID: uuidBytes(zero)}, - {BlockID: uuidBytes(eff)}, + {BlockID: zero}, + {BlockID: eff}, }, }, previousCompactedPerTenant: PerTenantCompacted{ "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(zero)}}, - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(aaa)}}, - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(eff)}}, + {BlockMeta: backend.BlockMeta{BlockID: zero}}, + {BlockMeta: backend.BlockMeta{BlockID: aaa}}, + {BlockMeta: backend.BlockMeta{BlockID: eff}}, }, }, currentPerTenant: PerTenant{ "test2": []*backend.BlockMeta{ - {BlockID: uuidBytes(zero)}, - {BlockID: uuidBytes(eff)}, + {BlockID: zero}, + {BlockID: eff}, }, }, currentCompactedPerTenant: PerTenantCompacted{ "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(zero)}}, - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(aaa)}}, - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(eff)}}, + {BlockMeta: backend.BlockMeta{BlockID: zero}}, + {BlockMeta: backend.BlockMeta{BlockID: aaa}}, + {BlockMeta: backend.BlockMeta{BlockID: eff}}, }, }, expectedPerTenant: PerTenant{ "test": []*backend.BlockMeta{}, "test2": []*backend.BlockMeta{ - {BlockID: uuidBytes(zero)}, - {BlockID: uuidBytes(eff)}, + {BlockID: zero}, + {BlockID: eff}, }, }, expectedCompactedPerTenant: PerTenantCompacted{ "test": []*backend.CompactedBlockMeta{ - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(zero)}}, - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(aaa)}}, - {BlockMeta: backend.BlockMeta{BlockID: uuidBytes(eff)}}, + {BlockMeta: backend.BlockMeta{BlockID: zero}}, + {BlockMeta: backend.BlockMeta{BlockID: aaa}}, + {BlockMeta: backend.BlockMeta{BlockID: eff}}, }, "test2": []*backend.CompactedBlockMeta{}, }, - expectedBlockMetaCalls: map[string]map[uuid.UUID]int{}, + expectedBlockMetaCalls: map[string]map[google_uuid.UUID]int{}, }, } @@ -942,12 +943,12 @@ func TestPollComparePreviousResults(t *testing.T) { for tenantID, expectedMetas := range tc.expectedPerTenant { l := metas[tenantID] sort.Slice(l, func(i, j int) bool { - x := bytes.Compare(l[i].BlockID[:], l[j].BlockID[:]) + x := bytes.Compare(l[i].BlockID.UUID[:], l[j].BlockID.UUID[:]) return x > 0 }) sort.Slice(expectedMetas, func(i, j int) bool { - x := bytes.Compare(expectedMetas[i].BlockID[:], expectedMetas[j].BlockID[:]) + x := bytes.Compare(expectedMetas[i].BlockID.UUID[:], expectedMetas[j].BlockID.UUID[:]) return x > 0 }) @@ -958,12 +959,12 @@ func TestPollComparePreviousResults(t *testing.T) { for tenantID, expectedCompactedMetas := range tc.expectedCompactedPerTenant { l := compactedMetas[tenantID] sort.Slice(l, func(i, j int) bool { - x := bytes.Compare(l[i].BlockID[:], l[j].BlockID[:]) + x := bytes.Compare(l[i].BlockID.UUID[:], l[j].BlockID.UUID[:]) return x > 0 }) sort.Slice(expectedCompactedMetas, func(i, j int) bool { - x := bytes.Compare(expectedCompactedMetas[i].BlockID[:], expectedCompactedMetas[j].BlockID[:]) + x := bytes.Compare(expectedCompactedMetas[i].BlockID.UUID[:], expectedCompactedMetas[j].BlockID.UUID[:]) return x > 0 }) require.Equal(t, expectedCompactedMetas, l) @@ -1044,7 +1045,7 @@ func newBlockMetas(count int) []*backend.BlockMeta { metas := make([]*backend.BlockMeta, count) for i := 0; i < count; i++ { metas[i] = &backend.BlockMeta{ - BlockID: []byte(uuid.New().String()), + BlockID: uuid.UUID{UUID: google_uuid.New()}, } } @@ -1056,7 +1057,7 @@ func newCompactedMetas(count int) []*backend.CompactedBlockMeta { for i := 0; i < count; i++ { metas[i] = &backend.CompactedBlockMeta{ BlockMeta: backend.BlockMeta{ - BlockID: []byte(uuid.New().String()), + BlockID: uuid.UUID{UUID: google_uuid.New()}, }, } } @@ -1102,9 +1103,7 @@ func newPerTenantCompacted(tenantCount, blockCount int) PerTenantCompacted { func newMockCompactor(list PerTenantCompacted, expectsError bool) backend.Compactor { return &backend.MockCompactor{ - BlockMetaFn: func(blockID uuid.UUID, tenantID string) (*backend.CompactedBlockMeta, error) { - id := []byte(blockID.String()) - + BlockMetaFn: func(blockID google_uuid.UUID, tenantID string) (*backend.CompactedBlockMeta, error) { if expectsError { return nil, errors.New("err") } @@ -1115,7 +1114,7 @@ func newMockCompactor(list PerTenantCompacted, expectsError bool) backend.Compac } for _, m := range l { - if bytes.Equal(m.BlockID, id) { + if m.BlockID.UUID == blockID { return m, nil } } @@ -1142,48 +1141,36 @@ func newMockReader(list PerTenant, compactedList PerTenantCompacted, expectsErro return &backend.MockReader{ T: tenants, - BlocksFn: func(_ context.Context, tenantID string) ([]uuid.UUID, []uuid.UUID, error) { + BlocksFn: func(_ context.Context, tenantID string) ([]google_uuid.UUID, []google_uuid.UUID, error) { if expectsError { return nil, nil, errors.New("err") } blocks := list[tenantID] - uuids := []uuid.UUID{} - compactedUUIDs := []uuid.UUID{} + uuids := []google_uuid.UUID{} + compactedUUIDs := []google_uuid.UUID{} for _, b := range blocks { - - id, err := uuid.ParseBytes(b.BlockID) - if err != nil { - return nil, nil, err - } - - uuids = append(uuids, id) + uuids = append(uuids, b.BlockID.UUID) } compactedBlocks := compactedList[tenantID] for _, b := range compactedBlocks { - id, err := uuid.ParseBytes(b.BlockID) - if err != nil { - return nil, nil, err - } - compactedUUIDs = append(compactedUUIDs, id) + compactedUUIDs = append(compactedUUIDs, b.BlockID.UUID) } return uuids, compactedUUIDs, nil }, - BlockMetaCalls: make(map[string]map[uuid.UUID]int), - BlockMetaFn: func(_ context.Context, blockID uuid.UUID, tenantID string) (*backend.BlockMeta, error) { + BlockMetaCalls: make(map[string]map[google_uuid.UUID]int), + BlockMetaFn: func(_ context.Context, blockID google_uuid.UUID, tenantID string) (*backend.BlockMeta, error) { if expectsError { return nil, errors.New("err") } - id := []byte(blockID.String()) - l, ok := list[tenantID] if !ok { return nil, backend.ErrDoesNotExist } for _, m := range l { - if bytes.Equal(m.BlockID, id) { + if m.BlockID.UUID == blockID { return m, nil } } @@ -1200,7 +1187,3 @@ func newBlocklist(metas PerTenant, compactedMetas PerTenantCompacted) *List { return l } - -func uuidBytes(u uuid.UUID) []byte { - return []byte(u.String()) -} From c51381a5c34bc5545ec607bfd1602a4e967ff26f Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Tue, 10 Sep 2024 21:12:29 +0000 Subject: [PATCH 07/71] Test WriteTenantIndex --- tempodb/backend/raw.go | 17 ++++++++++++++--- tempodb/backend/raw_test.go | 18 ++++++++++-------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/tempodb/backend/raw.go b/tempodb/backend/raw.go index 4fc463860d6..9026a693b27 100644 --- a/tempodb/backend/raw.go +++ b/tempodb/backend/raw.go @@ -124,17 +124,28 @@ func (w *writer) WriteTenantIndex(ctx context.Context, tenantID string, meta []* if err != nil && !errors.Is(err, ErrDoesNotExist) { return err } + + err = w.w.Delete(ctx, TenantIndexNameProto, []string{tenantID}, nil) + if err != nil && !errors.Is(err, ErrDoesNotExist) { + return err + } + return nil } - b := newTenantIndex(meta, compactedMeta) + var ( + b = newTenantIndex(meta, compactedMeta) + buf = &bytes.Buffer{} + ) - indexBytes, err := b.marshal() + err := new(jsonpb.Marshaler).Marshal(buf, b) if err != nil { return err } - err = w.w.Write(ctx, TenantIndexName, KeyPath([]string{tenantID}), bytes.NewReader(indexBytes), int64(len(indexBytes)), nil) + indexBytes := buf.Bytes() + + err = w.w.Write(ctx, TenantIndexNameProto, KeyPath([]string{tenantID}), bytes.NewReader(indexBytes), int64(len(indexBytes)), nil) if err != nil { return err } diff --git a/tempodb/backend/raw_test.go b/tempodb/backend/raw_test.go index 960954c54d2..d1fdddb1843 100644 --- a/tempodb/backend/raw_test.go +++ b/tempodb/backend/raw_test.go @@ -1,11 +1,12 @@ package backend import ( + "bytes" "context" "encoding/json" "testing" - "github.com/google/go-cmp/cmp" + "github.com/gogo/protobuf/jsonpb" "github.com/google/uuid" "github.com/stretchr/testify/assert" ) @@ -35,8 +36,12 @@ func TestWriter(t *testing.T) { assert.NoError(t, err) assert.True(t, m.closeAppendCalled) + // TODO: we want to check the json marshaling will unmarshal with jsonpb. + // TODO: we also want to check that we can round-trip with jsonpb. + meta := NewBlockMeta("test", uuid.New(), "blerg", EncGZIP, "glarg") - expected, _ = json.Marshal(meta) + expected, err = json.Marshal(meta) + assert.NoError(t, err) err = w.WriteBlockMeta(ctx, meta) assert.NoError(t, err) assert.Equal(t, expected, m.writeBuffer) @@ -44,20 +49,17 @@ func TestWriter(t *testing.T) { err = w.WriteTenantIndex(ctx, "test", []*BlockMeta{meta}, nil) assert.NoError(t, err) - idx := &TenantIndex{} - err = idx.unmarshal(m.writeBuffer) + pbidx := &TenantIndex{} + err = json.Unmarshal(m.writeBuffer, pbidx) assert.NoError(t, err) - assert.True(t, cmp.Equal([]*BlockMeta{meta}, idx.Meta)) // using cmp.Equal to compare json datetimes - assert.True(t, cmp.Equal([]*CompactedBlockMeta(nil), idx.CompactedMeta)) // using cmp.Equal to compare json datetimes - // When there are no blocks, the tenant index should be deleted assert.Equal(t, map[string]map[string]int(nil), w.(*writer).w.(*MockRawWriter).deleteCalls) err = w.WriteTenantIndex(ctx, "test", nil, nil) assert.NoError(t, err) - expectedDeleteMap := map[string]map[string]int{TenantIndexName: {"test": 1}} + expectedDeleteMap := map[string]map[string]int{TenantIndexName: {"test": 1}, TenantIndexNameProto: {"test": 1}} assert.Equal(t, expectedDeleteMap, w.(*writer).w.(*MockRawWriter).deleteCalls) // When a backend returns ErrDoesNotExist, the tenant index should be deleted, but no error should be returned if the tenant index does not exist From b2b7ad59b4267fd9672ce66a75a9078675e5bd73 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Tue, 10 Sep 2024 21:45:54 +0000 Subject: [PATCH 08/71] Implement json for uuid --- pkg/uuid/uuid.go | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/pkg/uuid/uuid.go b/pkg/uuid/uuid.go index ab2a9e9b3f6..a017e09da29 100644 --- a/pkg/uuid/uuid.go +++ b/pkg/uuid/uuid.go @@ -1,6 +1,8 @@ package uuid import ( + "encoding/json" + google_uuid "github.com/google/uuid" ) @@ -8,12 +10,12 @@ type UUID struct { google_uuid.UUID } -func (u *UUID) Size() int { - return 16 +func (u UUID) Marshal() ([]byte, error) { + return u.MarshalBinary() } func (u *UUID) MarshalTo(data []byte) (n int, err error) { - b, err := u.UUID.MarshalBinary() + b, err := u.MarshalBinary() if err != nil { return 0, err } @@ -22,10 +24,30 @@ func (u *UUID) MarshalTo(data []byte) (n int, err error) { } func (u *UUID) Unmarshal(data []byte) error { - err := u.UUID.UnmarshalBinary(data) + err := u.UnmarshalBinary(data) if err != nil { return err } return nil } + +func (u *UUID) Size() int { + return 16 +} + +func (u UUID) MarshalJSON() ([]byte, error) { + return json.Marshal(u.UUID.String()) +} + +func (u *UUID) UnmarshalJSON(data []byte) error { + uu := google_uuid.UUID{} + err := json.Unmarshal(data, &uu) + if err != nil { + return err + } + + u.UUID = uu + + return nil +} From 04cb211f2002b933db52f36a196472b5950f5286 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Tue, 10 Sep 2024 21:47:04 +0000 Subject: [PATCH 09/71] Almost functional backend tests --- tempodb/backend/block_meta.go | 134 ++- tempodb/backend/block_meta_test.go | 13 +- tempodb/backend/cache/cache.go | 2 +- tempodb/backend/encoding.go | 21 + tempodb/backend/local/local_test.go | 13 +- tempodb/backend/raw.go | 84 +- tempodb/backend/raw_test.go | 30 +- tempodb/backend/readerat.go | 4 +- tempodb/backend/tenantindex.go | 83 +- tempodb/backend/tenantindex_test.go | 3 + tempodb/backend/v1.pb.go | 1502 +++++++++++++++++++++++++++ tempodb/backend/v1/v1.proto | 4 +- 12 files changed, 1820 insertions(+), 73 deletions(-) create mode 100644 tempodb/backend/v1.pb.go diff --git a/tempodb/backend/block_meta.go b/tempodb/backend/block_meta.go index 3d06a6de0d8..6c5a6ee87d7 100644 --- a/tempodb/backend/block_meta.go +++ b/tempodb/backend/block_meta.go @@ -7,10 +7,11 @@ import ( "time" "github.com/cespare/xxhash/v2" - "github.com/google/uuid" + google_uuid "github.com/google/uuid" "github.com/grafana/tempo/pkg/tempopb" "github.com/grafana/tempo/pkg/traceql" + "github.com/grafana/tempo/pkg/uuid" ) // DedicatedColumnType is the type of the values in the dedicated attribute column. Only 'string' is supported. @@ -82,22 +83,45 @@ func (s DedicatedColumnScope) ToTempopb() (tempopb.DedicatedColumn_Scope, error) } } -type CompactedBlockMeta struct { +type compactedBlockMeta struct { CompactedTime time.Time `json:"compactedTime"` BlockMeta } +// func (b *CompactedBlockMeta) ToBackendV1Proto() (*CompactedBlockMeta, error) { +// bm, err := b.BlockMeta.ToBackendV1Proto() +// if err != nil { +// return nil, err +// } +// +// return &CompactedBlockMeta{ +// BlockMeta: *bm, +// CompactedTime: b.CompactedTime, +// }, nil +// } +// +// func (b *CompactedBlockMeta) FromBackendV1Proto(pb *CompactedBlockMeta) error { +// err := b.BlockMeta.FromBackendV1Proto(&pb.BlockMeta) +// if err != nil { +// return err +// } +// +// b.CompactedTime = pb.CompactedTime +// +// return nil +// } + const ( DefaultReplicationFactor = 0 // Replication factor for blocks from the ingester. This is the default value to indicate RF3. MetricsGeneratorReplicationFactor = 1 ) // The BlockMeta data that is stored for each individual block. -type BlockMeta struct { +type blockMeta struct { // A Version that indicates the block format. This includes specifics of how the indexes and data is stored. Version string `json:"format"` // BlockID is a unique identifier of the block. - BlockID uuid.UUID `json:"blockID"` + BlockID google_uuid.UUID `json:"blockID"` // A TenantID that defines the tenant to which this block belongs. TenantID string `json:"tenantID"` // StartTime roughly matches when the first obj was written to this block. It is used to determine block. @@ -192,14 +216,14 @@ func (dcs *DedicatedColumns) UnmarshalJSON(b []byte) error { return nil } -func NewBlockMeta(tenantID string, blockID uuid.UUID, version string, encoding Encoding, dataEncoding string) *BlockMeta { +func NewBlockMeta(tenantID string, blockID google_uuid.UUID, version string, encoding Encoding, dataEncoding string) *BlockMeta { return NewBlockMetaWithDedicatedColumns(tenantID, blockID, version, encoding, dataEncoding, nil) } -func NewBlockMetaWithDedicatedColumns(tenantID string, blockID uuid.UUID, version string, encoding Encoding, dataEncoding string, dc DedicatedColumns) *BlockMeta { +func NewBlockMetaWithDedicatedColumns(tenantID string, blockID google_uuid.UUID, version string, encoding Encoding, dataEncoding string, dc DedicatedColumns) *BlockMeta { b := &BlockMeta{ Version: version, - BlockID: blockID, + BlockID: uuid.UUID{UUID: blockID}, TenantID: tenantID, Encoding: encoding, DataEncoding: dataEncoding, @@ -233,6 +257,72 @@ func (b *BlockMeta) DedicatedColumnsHash() uint64 { return b.DedicatedColumns.Hash() } +// func (b *BlockMeta) ToBackendV1Proto() (*BlockMeta, error) { +// blockID, err := b.BlockID.MarshalText() +// if err != nil { +// return nil, err +// } +// +// m := &BlockMeta{ +// Version: b.Version, +// BlockId: blockID, +// TenantId: b.TenantID, +// StartTime: b.StartTime, +// EndTime: b.EndTime, +// TotalObjects: int32(b.TotalObjects), +// Size_: b.Size, +// CompactionLevel: uint32(b.CompactionLevel), +// Encoding: uint32(b.Encoding), +// IndexPageSize: b.IndexPageSize, +// TotalRecords: b.TotalRecords, +// DataEncoding: b.DataEncoding, +// BloomShardCount: uint32(b.BloomShardCount), +// FooterSize: b.FooterSize, +// ReplicationFactor: uint32(b.ReplicationFactor), +// } +// +// dc, err := b.DedicatedColumns.ToTempopb() +// if err != nil { +// return nil, err +// } +// m.DedicatedColumns = dc +// +// return m, nil +// } + +// func (b *BlockMeta) FromBackendV1Proto(pb *BlockMeta) error { +// blockID, err := uuid.ParseBytes(pb.BlockId) +// if err != nil { +// return err +// } +// +// b.Version = pb.Version +// b.BlockID = blockID +// b.TenantID = pb.TenantId +// b.StartTime = pb.StartTime +// b.EndTime = pb.EndTime +// b.TotalObjects = int(pb.TotalObjects) +// b.Size = pb.Size_ +// b.CompactionLevel = uint8(pb.CompactionLevel) +// b.Encoding = Encoding(pb.Encoding) +// b.IndexPageSize = pb.IndexPageSize +// b.TotalRecords = pb.TotalRecords +// b.DataEncoding = pb.DataEncoding +// b.BloomShardCount = uint16(pb.BloomShardCount) +// b.FooterSize = pb.FooterSize +// b.ReplicationFactor = uint8(pb.ReplicationFactor) +// dcs, err := DedicatedColumnsFromTempopb(pb.DedicatedColumns) +// if err != nil { +// return err +// } +// +// if len(dcs) > 0 { +// b.DedicatedColumns = dcs +// } +// +// return nil +// } + func DedicatedColumnsFromTempopb(tempopbCols []*tempopb.DedicatedColumn) (DedicatedColumns, error) { cols := make(DedicatedColumns, 0, len(tempopbCols)) @@ -337,3 +427,33 @@ func (dcs DedicatedColumns) Hash() uint64 { } return h.Sum64() } + +func (dcs DedicatedColumns) Size() int { + // FIXME: I don't think this is right. Since we're not marshaling to proto. + + var s int + pb, err := dcs.ToTempopb() + if err != nil { + return 0 + } + + for _, i := range pb { + s += i.Size() + } + + return s +} + +func (dcs DedicatedColumns) MarshalTo(data []byte) (n int, err error) { + bb, err := json.Marshal(dcs) + if err != nil { + return 0, err + } + copy(data, bb) + + return len(bb), nil +} + +func (dcs DedicatedColumns) Unmarshal(data []byte) error { + return json.Unmarshal(data, &dcs) +} diff --git a/tempodb/backend/block_meta_test.go b/tempodb/backend/block_meta_test.go index 1c7d7fa398e..4ea09299236 100644 --- a/tempodb/backend/block_meta_test.go +++ b/tempodb/backend/block_meta_test.go @@ -6,11 +6,12 @@ import ( "testing" "time" - "github.com/google/uuid" + google_uuid "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/grafana/tempo/pkg/tempopb" + "github.com/grafana/tempo/pkg/uuid" ) const ( @@ -22,10 +23,10 @@ func TestNewBlockMeta(t *testing.T) { testEncoding := EncLZ4_256k testDataEncoding := "blarg" - id := uuid.New() + id := google_uuid.New() b := NewBlockMeta(testTenantID, id, testVersion, testEncoding, testDataEncoding) - assert.Equal(t, id, b.BlockID) + assert.Equal(t, id, b.BlockID.UUID) assert.Equal(t, testTenantID, b.TenantID) assert.Equal(t, testVersion, b.Version) assert.Equal(t, testEncoding, b.Encoding) @@ -41,7 +42,7 @@ func TestBlockMetaObjectAdded(t *testing.T) { ends []uint32 expectedStart time.Time expectedEnd time.Time - expectedObjects int + expectedObjects int32 }{ {}, { @@ -99,12 +100,12 @@ func TestBlockMetaParsing(t *testing.T) { meta := BlockMeta{ Version: "vParquet3", - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, TenantID: "single-tenant", StartTime: timeParse("2021-01-01T00:00:00.0000000Z"), EndTime: timeParse("2021-01-02T00:00:00.0000000Z"), TotalObjects: 10, - Size: 12345, + Size_: 12345, CompactionLevel: 1, Encoding: EncZstd, IndexPageSize: 250000, diff --git a/tempodb/backend/cache/cache.go b/tempodb/backend/cache/cache.go index cd58550fe30..1099d46809d 100644 --- a/tempodb/backend/cache/cache.go +++ b/tempodb/backend/cache/cache.go @@ -202,7 +202,7 @@ func (r *readerWriter) cacheFor(cacheInfo *backend.CacheInfo) cache.Cache { } // compaction level is _atleast_ CacheMinCompactionLevel - if r.cfgBloom.CacheMinCompactionLevel > 0 && cacheInfo.Meta.CompactionLevel > r.cfgBloom.CacheMinCompactionLevel { + if r.cfgBloom.CacheMinCompactionLevel > 0 && cacheInfo.Meta.CompactionLevel > uint32(r.cfgBloom.CacheMinCompactionLevel) { return nil } diff --git a/tempodb/backend/encoding.go b/tempodb/backend/encoding.go index 62d4c35c906..53414e57342 100644 --- a/tempodb/backend/encoding.go +++ b/tempodb/backend/encoding.go @@ -105,6 +105,27 @@ func (e Encoding) MarshalJSON() ([]byte, error) { return buffer.Bytes(), nil } +func (e Encoding) Marshal() ([]byte, error) { + return e.MarshalJSON() +} + +func (e *Encoding) MarshalTo(data []byte) (n int, err error) { + b, err := e.Marshal() + if err != nil { + return 0, err + } + + return copy(data, b), nil +} + +func (e *Encoding) Unmarshal(data []byte) error { + return e.UnmarshalJSON(data) +} + +func (e *Encoding) Size() int { + return 1 +} + // ParseEncoding parses a chunk encoding (compression algorithm) by its name. func ParseEncoding(enc string) (Encoding, error) { for _, e := range SupportedEncoding { diff --git a/tempodb/backend/local/local_test.go b/tempodb/backend/local/local_test.go index 31c3fe59501..ab7d1bb255e 100644 --- a/tempodb/backend/local/local_test.go +++ b/tempodb/backend/local/local_test.go @@ -38,7 +38,7 @@ func TestReadWrite(t *testing.T) { } fakeMeta := &backend.BlockMeta{ - BlockID: blockID, + BlockId: []byte(blockID.String()), } fakeObject := make([]byte, 20) @@ -46,15 +46,18 @@ func TestReadWrite(t *testing.T) { _, err = crand.Read(fakeObject) assert.NoError(t, err, "unexpected error creating fakeObject") + blockID, err = uuid.ParseBytes(fakeMeta.BlockId) + assert.NoError(t, err, "unexpected error parsing blockID") + ctx := context.Background() for _, id := range tenantIDs { - fakeMeta.TenantID = id - err = w.Write(ctx, objectName, backend.KeyPathForBlock(fakeMeta.BlockID, id), bytes.NewReader(fakeObject), int64(len(fakeObject)), nil) + fakeMeta.TenantId = id + err = w.Write(ctx, objectName, backend.KeyPathForBlock(blockID, id), bytes.NewReader(fakeObject), int64(len(fakeObject)), nil) assert.NoError(t, err, "unexpected error writing") - err = w.Write(ctx, backend.MetaName, backend.KeyPathForBlock(fakeMeta.BlockID, id), bytes.NewReader(fakeObject), int64(len(fakeObject)), nil) + err = w.Write(ctx, backend.MetaName, backend.KeyPathForBlock(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(fakeMeta.BlockID, id), bytes.NewReader(fakeObject), int64(len(fakeObject)), nil) + err = w.Write(ctx, backend.CompactedMetaName, backend.KeyPathForBlock(blockID, id), bytes.NewReader(fakeObject), int64(len(fakeObject)), nil) assert.NoError(t, err, "unexpected error meta.compacted.json") } diff --git a/tempodb/backend/raw.go b/tempodb/backend/raw.go index 9026a693b27..40c46ece5e2 100644 --- a/tempodb/backend/raw.go +++ b/tempodb/backend/raw.go @@ -5,19 +5,26 @@ import ( "context" "encoding/json" "errors" + "fmt" "io" "path" "time" - "github.com/google/uuid" + "github.com/gogo/protobuf/jsonpb" + google_uuid "github.com/google/uuid" tempo_io "github.com/grafana/tempo/pkg/io" ) const ( + // JSON MetaName = "meta.json" CompactedMetaName = "meta.compacted.json" TenantIndexName = "index.json.gz" + + // Proto + TenantIndexNameProto = "index" + // File name for the cluster seed file. ClusterSeedFileName = "tempo_cluster_seed.json" ) @@ -53,7 +60,7 @@ type RawReader interface { // List returns all objects one level beneath the provided keypath List(ctx context.Context, keypath KeyPath) ([]string, error) // ListBlocks returns all blockIDs and compactedBlockIDs for a tenant. - ListBlocks(ctx context.Context, tenant string) (blockIDs []uuid.UUID, compactedBlockIDs []uuid.UUID, err error) + ListBlocks(ctx context.Context, tenant string) (blockIDs []google_uuid.UUID, compactedBlockIDs []google_uuid.UUID, err error) // Find executes the FindFunc for each object in the backend starting at the specified keypath. Collection of these objects is the callers responsibility. Find(ctx context.Context, keypath KeyPath, f FindFunc) error // Read is for streaming entire objects from the backend. There will be an attempt to retrieve this from cache if shouldCache is true. @@ -83,19 +90,21 @@ func NewWriter(w RawWriter) Writer { // ) // Write implements backend.Writer -func (w *writer) Write(ctx context.Context, name string, blockID uuid.UUID, tenantID string, buffer []byte, cacheInfo *CacheInfo) error { +func (w *writer) Write(ctx context.Context, name string, blockID google_uuid.UUID, tenantID string, buffer []byte, cacheInfo *CacheInfo) error { return w.w.Write(ctx, name, KeyPathForBlock(blockID, tenantID), bytes.NewReader(buffer), int64(len(buffer)), cacheInfo) } // Write implements backend.Writer -func (w *writer) StreamWriter(ctx context.Context, name string, blockID uuid.UUID, tenantID string, data io.Reader, size int64) error { +func (w *writer) StreamWriter(ctx context.Context, name string, blockID google_uuid.UUID, tenantID string, data io.Reader, size int64) error { return w.w.Write(ctx, name, KeyPathForBlock(blockID, tenantID), data, size, nil) } // Write implements backend.Writer func (w *writer) WriteBlockMeta(ctx context.Context, meta *BlockMeta) error { - blockID := meta.BlockID - tenantID := meta.TenantID + var ( + blockID = meta.BlockID.UUID + tenantID = meta.TenantID + ) bMeta, err := json.Marshal(meta) if err != nil { @@ -106,7 +115,7 @@ func (w *writer) WriteBlockMeta(ctx context.Context, meta *BlockMeta) error { } // Write implements backend.Writer -func (w *writer) Append(ctx context.Context, name string, blockID uuid.UUID, tenantID string, tracker AppendTracker, buffer []byte) (AppendTracker, error) { +func (w *writer) Append(ctx context.Context, name string, blockID google_uuid.UUID, tenantID string, tracker AppendTracker, buffer []byte) (AppendTracker, error) { return w.w.Append(ctx, name, KeyPathForBlock(blockID, tenantID), tracker, buffer) } @@ -170,7 +179,7 @@ func NewReader(r RawReader) Reader { } // Read implements backend.Reader -func (r *reader) Read(ctx context.Context, name string, blockID uuid.UUID, tenantID string, cacheInfo *CacheInfo) ([]byte, error) { +func (r *reader) Read(ctx context.Context, name string, blockID google_uuid.UUID, tenantID string, cacheInfo *CacheInfo) ([]byte, error) { objReader, size, err := r.r.Read(ctx, name, KeyPathForBlock(blockID, tenantID), cacheInfo) if err != nil { return nil, err @@ -180,12 +189,12 @@ func (r *reader) Read(ctx context.Context, name string, blockID uuid.UUID, tenan } // StreamReader implements backend.Reader -func (r *reader) StreamReader(ctx context.Context, name string, blockID uuid.UUID, tenantID string) (io.ReadCloser, int64, error) { +func (r *reader) StreamReader(ctx context.Context, name string, blockID google_uuid.UUID, tenantID string) (io.ReadCloser, int64, error) { return r.r.Read(ctx, name, KeyPathForBlock(blockID, tenantID), nil) } // ReadRange implements backend.Reader -func (r *reader) ReadRange(ctx context.Context, name string, blockID uuid.UUID, tenantID string, offset uint64, buffer []byte, cacheInfo *CacheInfo) error { +func (r *reader) ReadRange(ctx context.Context, name string, blockID google_uuid.UUID, tenantID string, offset uint64, buffer []byte, cacheInfo *CacheInfo) error { return r.r.ReadRange(ctx, name, KeyPathForBlock(blockID, tenantID), offset, buffer, cacheInfo) } @@ -205,25 +214,20 @@ func (r *reader) Tenants(ctx context.Context) ([]string, error) { } // Blocks implements backend.Reader -func (r *reader) Blocks(ctx context.Context, tenantID string) ([]uuid.UUID, []uuid.UUID, error) { +func (r *reader) Blocks(ctx context.Context, tenantID string) ([]google_uuid.UUID, []google_uuid.UUID, error) { return r.r.ListBlocks(ctx, tenantID) } // BlockMeta implements backend.Reader -func (r *reader) BlockMeta(ctx context.Context, blockID uuid.UUID, tenantID string) (*BlockMeta, error) { - reader, size, err := r.r.Read(ctx, MetaName, KeyPathForBlock(blockID, tenantID), nil) +func (r *reader) BlockMeta(ctx context.Context, blockID google_uuid.UUID, tenantID string) (*BlockMeta, error) { + reader, _, err := r.r.Read(ctx, MetaName, KeyPathForBlock(blockID, tenantID), nil) if err != nil { return nil, err } defer reader.Close() - bytes, err := tempo_io.ReadAllWithEstimate(reader, size) - if err != nil { - return nil, err - } - out := &BlockMeta{} - err = json.Unmarshal(bytes, out) + err = jsonpb.Unmarshal(reader, out) if err != nil { return nil, err } @@ -233,25 +237,12 @@ func (r *reader) BlockMeta(ctx context.Context, blockID uuid.UUID, tenantID stri // TenantIndex implements backend.Reader func (r *reader) TenantIndex(ctx context.Context, tenantID string) (*TenantIndex, error) { - reader, size, err := r.r.Read(ctx, TenantIndexName, KeyPath([]string{tenantID}), nil) - if err != nil { - return nil, err - } - - defer reader.Close() - - bytes, err := tempo_io.ReadAllWithEstimate(reader, size) + tenantIndex, err := r.tenantIndexProto(ctx, tenantID) if err != nil { return nil, err } - i := &TenantIndex{} - err = i.unmarshal(bytes) - if err != nil { - return nil, err - } - - return i, nil + return tenantIndex, nil } // Find implements backend.Reader @@ -264,8 +255,25 @@ func (r *reader) Shutdown() { r.r.Shutdown() } +func (r *reader) tenantIndexProto(ctx context.Context, tenantID string) (*TenantIndex, error) { + tenantIndexMessage := &TenantIndex{} + + reader, _, err := r.r.Read(ctx, TenantIndexNameProto, KeyPath([]string{tenantID}), nil) + if err != nil { + return nil, err + } + defer reader.Close() + + err = jsonpb.Unmarshal(reader, tenantIndexMessage) + if err == nil { + return tenantIndexMessage, nil + } + + return nil, fmt.Errorf("error reading tenant index proto: %w", err) +} + // KeyPathForBlock returns a correctly ordered keypath given a block id and tenantid -func KeyPathForBlock(blockID uuid.UUID, tenantID string) KeyPath { +func KeyPathForBlock(blockID google_uuid.UUID, tenantID string) KeyPath { return []string{tenantID, blockID.String()} } @@ -284,16 +292,16 @@ func KeyPathWithPrefix(keypath KeyPath, prefix string) KeyPath { } // MetaFileName returns the object name for the block meta given a block id and tenantid -func MetaFileName(blockID uuid.UUID, tenantID, prefix string) string { +func MetaFileName(blockID google_uuid.UUID, tenantID, prefix string) string { return path.Join(prefix, tenantID, blockID.String(), MetaName) } // CompactedMetaFileName returns the object name for the compacted block meta given a block id and tenantid -func CompactedMetaFileName(blockID uuid.UUID, tenantID, prefix string) string { +func CompactedMetaFileName(blockID google_uuid.UUID, tenantID, prefix string) string { return path.Join(prefix, tenantID, blockID.String(), CompactedMetaName) } // RootPath returns the root path for a block given a block id and tenantid -func RootPath(blockID uuid.UUID, tenantID, prefix string) string { +func RootPath(blockID google_uuid.UUID, tenantID, prefix string) string { return path.Join(prefix, tenantID, blockID.String()) } diff --git a/tempodb/backend/raw_test.go b/tempodb/backend/raw_test.go index d1fdddb1843..c51d0c58311 100644 --- a/tempodb/backend/raw_test.go +++ b/tempodb/backend/raw_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/gogo/protobuf/jsonpb" + "github.com/google/go-cmp/cmp" "github.com/google/uuid" "github.com/stretchr/testify/assert" ) @@ -49,10 +50,17 @@ func TestWriter(t *testing.T) { err = w.WriteTenantIndex(ctx, "test", []*BlockMeta{meta}, nil) assert.NoError(t, err) - pbidx := &TenantIndex{} - err = json.Unmarshal(m.writeBuffer, pbidx) + idx := &TenantIndex{} + err = json.Unmarshal(m.writeBuffer, idx) assert.NoError(t, err) + t.Logf("writeBuffer: %v", string(m.writeBuffer)) + + assert.Equal(t, []*BlockMeta{meta}, idx.Meta) + assert.True(t, cmp.Equal([]*BlockMeta{meta}, idx.Meta)) // using cmp.Equal to compare json datetimes + assert.Equal(t, []*CompactedBlockMeta(nil), idx.Meta) + assert.True(t, cmp.Equal([]*CompactedBlockMeta(nil), idx.CompactedMeta)) // using cmp.Equal to compare json datetimes + // When there are no blocks, the tenant index should be deleted assert.Equal(t, map[string]map[string]int(nil), w.(*writer).w.(*MockRawWriter).deleteCalls) @@ -110,21 +118,23 @@ func TestReader(t *testing.T) { assert.Nil(t, meta) expectedMeta := NewBlockMeta("test", uuid.New(), "blerg", EncGZIP, "glarg") - m.R, _ = json.Marshal(expectedMeta) + + var ( + bb = []byte{} + buf = bytes.NewBuffer(bb) + ) + err = new(jsonpb.Marshaler).Marshal(buf, expectedMeta) + assert.NoError(t, err) + m.R = buf.Bytes() + t.Logf("meta: %v", string(m.R)) meta, err = r.BlockMeta(ctx, uuid.New(), "test") assert.NoError(t, err) - assert.True(t, cmp.Equal(expectedMeta, meta)) + assert.Equal(t, expectedMeta, meta) // should fail b/c tenant index is not valid idx, err := r.TenantIndex(ctx, "test") assert.Error(t, err) assert.Nil(t, idx) - - expectedIdx := newTenantIndex([]*BlockMeta{expectedMeta}, nil) - m.R, _ = expectedIdx.marshal() - idx, err = r.TenantIndex(ctx, "test") - assert.NoError(t, err) - assert.True(t, cmp.Equal(expectedIdx, idx)) } func TestKeyPathForBlock(t *testing.T) { diff --git a/tempodb/backend/readerat.go b/tempodb/backend/readerat.go index f2071606d31..7d3439c9609 100644 --- a/tempodb/backend/readerat.go +++ b/tempodb/backend/readerat.go @@ -35,13 +35,13 @@ func NewContextReader(meta *BlockMeta, name string, r Reader) ContextReader { // ReadAt implements ContextReader func (b *backendReader) ReadAt(ctx context.Context, p []byte, off int64) (int, error) { - err := b.r.ReadRange(ctx, b.name, b.meta.BlockID, b.meta.TenantID, uint64(off), p, nil) + err := b.r.ReadRange(ctx, b.name, b.meta.BlockID.UUID, b.meta.TenantID, uint64(off), p, nil) return len(p), err } // ReadAll implements ContextReader func (b *backendReader) ReadAll(ctx context.Context) ([]byte, error) { - return b.r.Read(ctx, b.name, b.meta.BlockID, b.meta.TenantID, nil) + return b.r.Read(ctx, b.name, b.meta.BlockID.UUID, b.meta.TenantID, nil) } // Reader implements ContextReader diff --git a/tempodb/backend/tenantindex.go b/tempodb/backend/tenantindex.go index 594d5fc8b74..3f18da5a128 100644 --- a/tempodb/backend/tenantindex.go +++ b/tempodb/backend/tenantindex.go @@ -5,6 +5,7 @@ import ( "encoding/json" "time" + proto "github.com/gogo/protobuf/proto" "github.com/klauspost/compress/gzip" ) @@ -12,9 +13,11 @@ const ( internalFilename = "index.json" ) -// TenantIndex holds a list of all metas and compacted metas for a given tenant +var _ proto.Message = &TenantIndex{} + +// tenantIndex holds a list of all metas and compacted metas for a given tenant // it is probably stored in //blockindex.json.gz as a gzipped json file -type TenantIndex struct { +type tenantIndex struct { CreatedAt time.Time `json:"created_at"` Meta []*BlockMeta `json:"meta"` CompactedMeta []*CompactedBlockMeta `json:"compacted"` @@ -64,3 +67,79 @@ func (b *TenantIndex) unmarshal(buffer []byte) error { d := json.NewDecoder(gzipReader) return d.Decode(b) } + +// func (b *TenantIndex) proto() (*TenantIndex, error) { +// tenantIndex := &TenantIndex{ +// CreatedAt: b.CreatedAt, +// Meta: make([]*BlockMeta, 0, len(b.Meta)), +// CompactedMeta: make([]*CompactedBlockMeta, 0, len(b.CompactedMeta)), +// } +// +// var ( +// err error +// mPb *BlockMeta +// cPb *CompactedBlockMeta +// ) +// +// for _, m := range b.Meta { +// mPb, err = m.ToBackendV1Proto() +// if err != nil { +// return nil, err +// } +// +// tenantIndex.Meta = append(tenantIndex.Meta, mPb) +// } +// +// for _, m := range b.CompactedMeta { +// cPb, err = m.ToBackendV1Proto() +// if err != nil { +// return nil, err +// } +// +// tenantIndex.CompactedMeta = append(tenantIndex.CompactedMeta, cPb) +// } +// +// return tenantIndex, nil +// } + +// func (b *tenantIndex) fromProto(pb *TenantIndex) error { +// b.CreatedAt = pb.CreatedAt +// var ( +// meta = make([]*BlockMeta, 0, len(pb.Meta)) +// compactedMeta = make([]*CompactedBlockMeta, 0, len(pb.CompactedMeta)) +// ) +// +// var ( +// err error +// m *BlockMeta +// c *CompactedBlockMeta +// ) +// +// for _, mPb := range pb.Meta { +// m = &BlockMeta{} +// err = m.FromBackendV1Proto(mPb) +// if err != nil { +// return err +// } +// meta = append(meta, m) +// } +// +// if len(meta) > 0 { +// b.Meta = meta +// } +// +// for _, cPb := range pb.CompactedMeta { +// c = &CompactedBlockMeta{} +// err = c.FromBackendV1Proto(cPb) +// if err != nil { +// return err +// } +// compactedMeta = append(compactedMeta, c) +// } +// +// if len(compactedMeta) > 0 { +// b.CompactedMeta = compactedMeta +// } +// +// return nil +// } diff --git a/tempodb/backend/tenantindex_test.go b/tempodb/backend/tenantindex_test.go index 3a02d303d16..2f00d75398c 100644 --- a/tempodb/backend/tenantindex_test.go +++ b/tempodb/backend/tenantindex_test.go @@ -19,6 +19,7 @@ func TestIndexMarshalUnmarshal(t *testing.T) { }, { idx: &TenantIndex{ + CreatedAt: time.Now(), Meta: []*BlockMeta{ NewBlockMeta("test", uuid.New(), "v1", EncGZIP, "adsf"), NewBlockMeta("test", uuid.New(), "v2", EncNone, "adsf"), @@ -28,6 +29,7 @@ func TestIndexMarshalUnmarshal(t *testing.T) { }, { idx: &TenantIndex{ + CreatedAt: time.Now(), CompactedMeta: []*CompactedBlockMeta{ { BlockMeta: *NewBlockMeta("test", uuid.New(), "v1", EncGZIP, "adsf"), @@ -70,6 +72,7 @@ func TestIndexMarshalUnmarshal(t *testing.T) { } for _, tc := range tests { + // json buff, err := tc.idx.marshal() require.NoError(t, err) diff --git a/tempodb/backend/v1.pb.go b/tempodb/backend/v1.pb.go new file mode 100644 index 00000000000..359b374f304 --- /dev/null +++ b/tempodb/backend/v1.pb.go @@ -0,0 +1,1502 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: tempodb/backend/v1/v1.proto + +package backend + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + github_com_grafana_tempo_pkg_uuid "github.com/grafana/tempo/pkg/uuid" + _ "google.golang.org/protobuf/types/known/timestamppb" + io "io" + math "math" + math_bits "math/bits" + time "time" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf +var _ = time.Kitchen + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type BlockMeta struct { + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"format"` + BlockID github_com_grafana_tempo_pkg_uuid.UUID `protobuf:"bytes,2,opt,name=block_id,json=blockId,proto3,customtype=github.com/grafana/tempo/pkg/uuid.UUID" json:"blockID"` + TenantID string `protobuf:"bytes,5,opt,name=tenant_id,json=tenantId,proto3" json:"tenantID"` + StartTime time.Time `protobuf:"bytes,6,opt,name=start_time,json=startTime,proto3,stdtime" json:"startTime"` + EndTime time.Time `protobuf:"bytes,7,opt,name=end_time,json=endTime,proto3,stdtime" json:"endTime"` + TotalObjects int32 `protobuf:"varint,8,opt,name=total_objects,json=totalObjects,proto3" json:"totalObjects"` + Size_ uint64 `protobuf:"varint,9,opt,name=size,proto3" json:"size,omitempty"` + CompactionLevel uint32 `protobuf:"varint,10,opt,name=compaction_level,json=compactionLevel,proto3" json:"compactionLevel"` + Encoding Encoding `protobuf:"bytes,11,opt,name=encoding,proto3,customtype=Encoding" json:"encoding"` + IndexPageSize uint32 `protobuf:"varint,12,opt,name=index_page_size,json=indexPageSize,proto3" json:"indexPageSize"` + TotalRecords uint32 `protobuf:"varint,13,opt,name=total_records,json=totalRecords,proto3" json:"totalRecords"` + DataEncoding string `protobuf:"bytes,14,opt,name=data_encoding,json=dataEncoding,proto3" json:"dataEncoding"` + BloomShardCount uint32 `protobuf:"varint,15,opt,name=bloom_shard_count,json=bloomShardCount,proto3" json:"bloomShards"` + FooterSize uint32 `protobuf:"varint,16,opt,name=footer_size,json=footerSize,proto3" json:"footerSize"` + // repeated bytes dedicated_columns = 17 [(gogoproto.customtype) = "github.com/grafana/tempo/pkg/tempopb.DedicatedColumn"]; + // repeated bytes dedicated_columns = 17 [(gogoproto.customtype) = "github.com/grafana/tempo/tempodb/backend/meta.DedicatedColumn"]; + DedicatedColumns DedicatedColumns `protobuf:"bytes,17,opt,name=dedicated_columns,json=dedicatedColumns,proto3,customtype=DedicatedColumns" json:"dedicatedColumns,omitempty"` + // bytes dedicated_columns = 17; + // repeated tempopb.DedicatedColumn dedicated_columns = 17[(gogoproto.jsontag) = "dedicatedColumns,omitempty"]; + ReplicationFactor uint32 `protobuf:"varint,18,opt,name=replication_factor,json=replicationFactor,proto3" json:"replicationFactor,omitempty"` +} + +func (m *BlockMeta) Reset() { *m = BlockMeta{} } +func (m *BlockMeta) String() string { return proto.CompactTextString(m) } +func (*BlockMeta) ProtoMessage() {} +func (*BlockMeta) Descriptor() ([]byte, []int) { + return fileDescriptor_6bc10ae735c1a340, []int{0} +} +func (m *BlockMeta) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *BlockMeta) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_BlockMeta.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *BlockMeta) XXX_Merge(src proto.Message) { + xxx_messageInfo_BlockMeta.Merge(m, src) +} +func (m *BlockMeta) XXX_Size() int { + return m.Size() +} +func (m *BlockMeta) XXX_DiscardUnknown() { + xxx_messageInfo_BlockMeta.DiscardUnknown(m) +} + +var xxx_messageInfo_BlockMeta proto.InternalMessageInfo + +func (m *BlockMeta) GetVersion() string { + if m != nil { + return m.Version + } + return "" +} + +func (m *BlockMeta) GetTenantID() string { + if m != nil { + return m.TenantID + } + return "" +} + +func (m *BlockMeta) GetStartTime() time.Time { + if m != nil { + return m.StartTime + } + return time.Time{} +} + +func (m *BlockMeta) GetEndTime() time.Time { + if m != nil { + return m.EndTime + } + return time.Time{} +} + +func (m *BlockMeta) GetTotalObjects() int32 { + if m != nil { + return m.TotalObjects + } + return 0 +} + +func (m *BlockMeta) GetSize_() uint64 { + if m != nil { + return m.Size_ + } + return 0 +} + +func (m *BlockMeta) GetCompactionLevel() uint32 { + if m != nil { + return m.CompactionLevel + } + return 0 +} + +func (m *BlockMeta) GetIndexPageSize() uint32 { + if m != nil { + return m.IndexPageSize + } + return 0 +} + +func (m *BlockMeta) GetTotalRecords() uint32 { + if m != nil { + return m.TotalRecords + } + return 0 +} + +func (m *BlockMeta) GetDataEncoding() string { + if m != nil { + return m.DataEncoding + } + return "" +} + +func (m *BlockMeta) GetBloomShardCount() uint32 { + if m != nil { + return m.BloomShardCount + } + return 0 +} + +func (m *BlockMeta) GetFooterSize() uint32 { + if m != nil { + return m.FooterSize + } + return 0 +} + +func (m *BlockMeta) GetReplicationFactor() uint32 { + if m != nil { + return m.ReplicationFactor + } + return 0 +} + +type CompactedBlockMeta struct { + BlockMeta `protobuf:"bytes,1,opt,name=block_meta,json=blockMeta,proto3,embedded=block_meta" json:"block_meta"` + CompactedTime time.Time `protobuf:"bytes,2,opt,name=compacted_time,json=compactedTime,proto3,stdtime" json:"compacted_time"` +} + +func (m *CompactedBlockMeta) Reset() { *m = CompactedBlockMeta{} } +func (m *CompactedBlockMeta) String() string { return proto.CompactTextString(m) } +func (*CompactedBlockMeta) ProtoMessage() {} +func (*CompactedBlockMeta) Descriptor() ([]byte, []int) { + return fileDescriptor_6bc10ae735c1a340, []int{1} +} +func (m *CompactedBlockMeta) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CompactedBlockMeta) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CompactedBlockMeta.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CompactedBlockMeta) XXX_Merge(src proto.Message) { + xxx_messageInfo_CompactedBlockMeta.Merge(m, src) +} +func (m *CompactedBlockMeta) XXX_Size() int { + return m.Size() +} +func (m *CompactedBlockMeta) XXX_DiscardUnknown() { + xxx_messageInfo_CompactedBlockMeta.DiscardUnknown(m) +} + +var xxx_messageInfo_CompactedBlockMeta proto.InternalMessageInfo + +func (m *CompactedBlockMeta) GetCompactedTime() time.Time { + if m != nil { + return m.CompactedTime + } + return time.Time{} +} + +type TenantIndex struct { + CreatedAt time.Time `protobuf:"bytes,1,opt,name=created_at,json=createdAt,proto3,stdtime" json:"created_at"` + Meta []*BlockMeta `protobuf:"bytes,2,rep,name=meta,proto3" json:"meta,omitempty"` + CompactedMeta []*CompactedBlockMeta `protobuf:"bytes,3,rep,name=compacted_meta,json=compactedMeta,proto3" json:"compacted_meta,omitempty"` +} + +func (m *TenantIndex) Reset() { *m = TenantIndex{} } +func (m *TenantIndex) String() string { return proto.CompactTextString(m) } +func (*TenantIndex) ProtoMessage() {} +func (*TenantIndex) Descriptor() ([]byte, []int) { + return fileDescriptor_6bc10ae735c1a340, []int{2} +} +func (m *TenantIndex) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TenantIndex) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TenantIndex.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TenantIndex) XXX_Merge(src proto.Message) { + xxx_messageInfo_TenantIndex.Merge(m, src) +} +func (m *TenantIndex) XXX_Size() int { + return m.Size() +} +func (m *TenantIndex) XXX_DiscardUnknown() { + xxx_messageInfo_TenantIndex.DiscardUnknown(m) +} + +var xxx_messageInfo_TenantIndex proto.InternalMessageInfo + +func (m *TenantIndex) GetCreatedAt() time.Time { + if m != nil { + return m.CreatedAt + } + return time.Time{} +} + +func (m *TenantIndex) GetMeta() []*BlockMeta { + if m != nil { + return m.Meta + } + return nil +} + +func (m *TenantIndex) GetCompactedMeta() []*CompactedBlockMeta { + if m != nil { + return m.CompactedMeta + } + return nil +} + +func init() { + proto.RegisterType((*BlockMeta)(nil), "backend.v1.BlockMeta") + proto.RegisterType((*CompactedBlockMeta)(nil), "backend.v1.CompactedBlockMeta") + proto.RegisterType((*TenantIndex)(nil), "backend.v1.TenantIndex") +} + +func init() { proto.RegisterFile("tempodb/backend/v1/v1.proto", fileDescriptor_6bc10ae735c1a340) } + +var fileDescriptor_6bc10ae735c1a340 = []byte{ + // 785 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0x4f, 0x6b, 0xeb, 0x46, + 0x10, 0xb7, 0xf2, 0xf2, 0x62, 0x7b, 0x1d, 0xc7, 0xf6, 0x3e, 0x1e, 0x08, 0x3f, 0xf0, 0x9a, 0x50, + 0x8a, 0x1f, 0xbc, 0x4a, 0x24, 0x25, 0x85, 0x52, 0x08, 0xd4, 0x76, 0x0a, 0xe9, 0xdf, 0xa0, 0x24, + 0x97, 0x5e, 0xc4, 0x4a, 0xbb, 0x56, 0xd4, 0x48, 0x5a, 0x23, 0xad, 0x4d, 0x9b, 0x4f, 0x91, 0xaf, + 0xd0, 0xef, 0xd2, 0x43, 0x8e, 0x39, 0x96, 0x1e, 0xd4, 0xe2, 0xdc, 0x44, 0x3f, 0x44, 0xd9, 0x91, + 0x6c, 0xd9, 0x0e, 0x25, 0xef, 0x36, 0x33, 0xbf, 0xf9, 0xcd, 0xcc, 0x6f, 0xb4, 0x23, 0xf4, 0x4e, + 0xf2, 0x70, 0x2a, 0x98, 0x63, 0x3a, 0xd4, 0xbd, 0xe5, 0x11, 0x33, 0xe7, 0x47, 0xe6, 0xfc, 0xc8, + 0x98, 0xc6, 0x42, 0x0a, 0x8c, 0x8a, 0xa0, 0x31, 0x3f, 0xea, 0x12, 0x4f, 0x08, 0x2f, 0xe0, 0x26, + 0x20, 0xce, 0x6c, 0x62, 0x4a, 0x3f, 0xe4, 0x89, 0xa4, 0xe1, 0x34, 0x4f, 0xee, 0x7e, 0xe6, 0xf9, + 0xf2, 0x66, 0xe6, 0x18, 0xae, 0x08, 0x4d, 0x4f, 0x78, 0xa2, 0xcc, 0x54, 0x1e, 0x38, 0x60, 0xe5, + 0xe9, 0x87, 0xff, 0x56, 0x51, 0x7d, 0x18, 0x08, 0xf7, 0xf6, 0x07, 0x2e, 0x29, 0xfe, 0x04, 0x55, + 0xe7, 0x3c, 0x4e, 0x7c, 0x11, 0xe9, 0x5a, 0x5f, 0x1b, 0xd4, 0x87, 0x28, 0x4b, 0xc9, 0xde, 0x44, + 0xc4, 0x21, 0x95, 0xd6, 0x12, 0xc2, 0x36, 0xaa, 0x39, 0x8a, 0x62, 0xfb, 0x4c, 0xdf, 0xe9, 0x6b, + 0x83, 0xfd, 0xe1, 0xf8, 0x21, 0x25, 0x95, 0xbf, 0x52, 0xf2, 0xe9, 0x7a, 0xf3, 0x98, 0x4e, 0x68, + 0x44, 0x4d, 0x50, 0x66, 0x4e, 0x6f, 0x3d, 0x73, 0x36, 0xf3, 0x99, 0x71, 0x7d, 0x7d, 0x3e, 0x5e, + 0xa4, 0xa4, 0x0a, 0x4d, 0xcf, 0xc7, 0x59, 0x4a, 0xaa, 0x4e, 0x6e, 0x5a, 0x85, 0xc1, 0xf0, 0x09, + 0xaa, 0x4b, 0x1e, 0xd1, 0x48, 0xaa, 0x0e, 0xaf, 0x61, 0x10, 0x7d, 0x91, 0x92, 0xda, 0x15, 0x04, + 0x81, 0x54, 0x93, 0x85, 0x6d, 0x2d, 0x2d, 0x86, 0x2f, 0x10, 0x4a, 0x24, 0x8d, 0xa5, 0xad, 0x76, + 0xa2, 0xef, 0xf5, 0xb5, 0x41, 0xe3, 0xb8, 0x6b, 0xe4, 0x0b, 0x33, 0x96, 0x6b, 0x30, 0xae, 0x96, + 0x0b, 0x1b, 0xbe, 0x55, 0x53, 0x67, 0x29, 0xa9, 0x03, 0x4b, 0xc5, 0xef, 0xff, 0x26, 0x9a, 0x55, + 0xba, 0xf8, 0x5b, 0x54, 0xe3, 0x11, 0xcb, 0xeb, 0x55, 0x5f, 0xac, 0xf7, 0xa6, 0xa8, 0x57, 0xe5, + 0x11, 0x5b, 0x55, 0x5b, 0x3a, 0xf8, 0x04, 0x35, 0xa5, 0x90, 0x34, 0xb0, 0x85, 0xf3, 0x0b, 0x77, + 0x65, 0xa2, 0xd7, 0xfa, 0xda, 0xe0, 0xf5, 0xb0, 0x9d, 0xa5, 0x64, 0x1f, 0x80, 0x9f, 0xf2, 0xb8, + 0xb5, 0xe1, 0x61, 0x8c, 0x76, 0x13, 0xff, 0x8e, 0xeb, 0xf5, 0xbe, 0x36, 0xd8, 0xb5, 0xc0, 0xc6, + 0xa7, 0xa8, 0xed, 0x8a, 0x70, 0x4a, 0x5d, 0xe9, 0x8b, 0xc8, 0x0e, 0xf8, 0x9c, 0x07, 0x3a, 0xea, + 0x6b, 0x83, 0xe6, 0xf0, 0x4d, 0x96, 0x92, 0x56, 0x89, 0x7d, 0xaf, 0x20, 0x6b, 0x3b, 0x80, 0x3f, + 0x28, 0x59, 0xae, 0x60, 0x7e, 0xe4, 0xe9, 0x0d, 0xf8, 0x80, 0xed, 0xe2, 0x03, 0xd6, 0xce, 0x8a, + 0xb8, 0xb5, 0xca, 0xc0, 0x5f, 0xa2, 0x96, 0x1f, 0x31, 0xfe, 0xab, 0x3d, 0xa5, 0x1e, 0xb7, 0x61, + 0x98, 0x7d, 0x68, 0xd6, 0xc9, 0x52, 0xd2, 0x04, 0xe8, 0x82, 0x7a, 0xfc, 0xd2, 0xbf, 0xe3, 0xd6, + 0xa6, 0x5b, 0x6a, 0x8e, 0xb9, 0x2b, 0x62, 0x96, 0xe8, 0x4d, 0x20, 0x96, 0x9a, 0xad, 0x3c, 0x6e, + 0x6d, 0x78, 0x8a, 0xc6, 0xa8, 0xa4, 0xf6, 0x6a, 0xc8, 0x03, 0x78, 0x03, 0x40, 0x53, 0xc0, 0x6a, + 0xc8, 0x0d, 0x0f, 0x7f, 0x85, 0x3a, 0x4e, 0x20, 0x44, 0x68, 0x27, 0x37, 0x34, 0x66, 0xb6, 0x2b, + 0x66, 0x91, 0xd4, 0x5b, 0xd0, 0xb1, 0x95, 0xa5, 0xa4, 0x01, 0xe0, 0xa5, 0xc2, 0x12, 0xab, 0x55, + 0x3a, 0x23, 0x95, 0x87, 0x4d, 0xd4, 0x98, 0x08, 0x21, 0x79, 0x9c, 0x2b, 0x6c, 0x03, 0xed, 0x20, + 0x4b, 0x09, 0xca, 0xc3, 0x20, 0x6f, 0xcd, 0xc6, 0x2e, 0xea, 0x30, 0xce, 0x7c, 0x97, 0x4a, 0xae, + 0x7a, 0x05, 0xb3, 0x30, 0x4a, 0xf4, 0x0e, 0x6c, 0xf3, 0x8b, 0x62, 0x9b, 0xed, 0xf1, 0x32, 0x61, + 0x94, 0xe3, 0x59, 0x4a, 0xba, 0x6c, 0x2b, 0xf6, 0x41, 0x84, 0xbe, 0xba, 0x11, 0xf9, 0x9b, 0xd5, + 0xde, 0xc6, 0xf0, 0x8f, 0x08, 0xc7, 0x7c, 0x1a, 0xa8, 0xa0, 0xfa, 0xd4, 0x13, 0xea, 0x4a, 0x11, + 0xeb, 0x18, 0x86, 0x23, 0x59, 0x4a, 0xde, 0xad, 0xa1, 0xdf, 0x00, 0xb8, 0x56, 0xae, 0xf3, 0x0c, + 0x3c, 0xfc, 0x5d, 0x43, 0x78, 0x94, 0xbf, 0x06, 0xce, 0xca, 0xbb, 0x3f, 0x45, 0x28, 0xbf, 0xe8, + 0x90, 0x4b, 0x0a, 0xa7, 0xdf, 0x38, 0x7e, 0x6b, 0x94, 0xbf, 0x1d, 0x63, 0x95, 0x3a, 0xac, 0x29, + 0x6d, 0x8f, 0xa9, 0xba, 0x13, 0x67, 0xc5, 0xff, 0x0e, 0x1d, 0xb8, 0xcb, 0xaa, 0xf9, 0xb5, 0xec, + 0xbc, 0x78, 0x2d, 0x50, 0x08, 0x4e, 0xa4, 0xb9, 0xe2, 0x2a, 0xf4, 0xf0, 0x0f, 0x0d, 0x35, 0x8a, + 0x4b, 0x57, 0x8f, 0x09, 0x8f, 0x10, 0x72, 0x63, 0x0e, 0x6b, 0xa6, 0xb2, 0x18, 0xee, 0xe3, 0x0a, + 0xd7, 0x0b, 0xde, 0xd7, 0x12, 0xbf, 0x47, 0xbb, 0xa0, 0x6d, 0xa7, 0xff, 0xea, 0x7f, 0xb5, 0x59, + 0x90, 0x82, 0xcf, 0xd6, 0xc5, 0x00, 0xe9, 0x15, 0x90, 0x7a, 0xeb, 0xa4, 0xe7, 0x4b, 0x5c, 0x93, + 0x01, 0x8b, 0x7a, 0xff, 0xb0, 0xe8, 0x69, 0x8f, 0x8b, 0x9e, 0xf6, 0xcf, 0xa2, 0xa7, 0xdd, 0x3f, + 0xf5, 0x2a, 0x8f, 0x4f, 0xbd, 0xca, 0x9f, 0x4f, 0xbd, 0xca, 0xcf, 0xad, 0xad, 0x9f, 0xbd, 0xb3, + 0x07, 0x2a, 0x3e, 0xff, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x02, 0x6e, 0xb1, 0xc7, 0x06, 0x06, 0x00, + 0x00, +} + +func (m *BlockMeta) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *BlockMeta) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *BlockMeta) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.ReplicationFactor != 0 { + i = encodeVarintV1(dAtA, i, uint64(m.ReplicationFactor)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x90 + } + { + size := m.DedicatedColumns.Size() + i -= size + if _, err := m.DedicatedColumns.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintV1(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x8a + if m.FooterSize != 0 { + i = encodeVarintV1(dAtA, i, uint64(m.FooterSize)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x80 + } + if m.BloomShardCount != 0 { + i = encodeVarintV1(dAtA, i, uint64(m.BloomShardCount)) + i-- + dAtA[i] = 0x78 + } + if len(m.DataEncoding) > 0 { + i -= len(m.DataEncoding) + copy(dAtA[i:], m.DataEncoding) + i = encodeVarintV1(dAtA, i, uint64(len(m.DataEncoding))) + i-- + dAtA[i] = 0x72 + } + if m.TotalRecords != 0 { + i = encodeVarintV1(dAtA, i, uint64(m.TotalRecords)) + i-- + dAtA[i] = 0x68 + } + if m.IndexPageSize != 0 { + i = encodeVarintV1(dAtA, i, uint64(m.IndexPageSize)) + i-- + dAtA[i] = 0x60 + } + { + size := m.Encoding.Size() + i -= size + if _, err := m.Encoding.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintV1(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x5a + if m.CompactionLevel != 0 { + i = encodeVarintV1(dAtA, i, uint64(m.CompactionLevel)) + i-- + dAtA[i] = 0x50 + } + if m.Size_ != 0 { + i = encodeVarintV1(dAtA, i, uint64(m.Size_)) + i-- + dAtA[i] = 0x48 + } + if m.TotalObjects != 0 { + i = encodeVarintV1(dAtA, i, uint64(m.TotalObjects)) + i-- + dAtA[i] = 0x40 + } + n1, err1 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.EndTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.EndTime):]) + if err1 != nil { + return 0, err1 + } + i -= n1 + i = encodeVarintV1(dAtA, i, uint64(n1)) + i-- + dAtA[i] = 0x3a + n2, err2 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.StartTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.StartTime):]) + if err2 != nil { + return 0, err2 + } + i -= n2 + i = encodeVarintV1(dAtA, i, uint64(n2)) + i-- + dAtA[i] = 0x32 + if len(m.TenantID) > 0 { + i -= len(m.TenantID) + copy(dAtA[i:], m.TenantID) + i = encodeVarintV1(dAtA, i, uint64(len(m.TenantID))) + i-- + dAtA[i] = 0x2a + } + { + size := m.BlockID.Size() + i -= size + if _, err := m.BlockID.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintV1(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Version) > 0 { + i -= len(m.Version) + copy(dAtA[i:], m.Version) + i = encodeVarintV1(dAtA, i, uint64(len(m.Version))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *CompactedBlockMeta) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CompactedBlockMeta) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CompactedBlockMeta) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + n3, err3 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CompactedTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.CompactedTime):]) + if err3 != nil { + return 0, err3 + } + i -= n3 + i = encodeVarintV1(dAtA, i, uint64(n3)) + i-- + dAtA[i] = 0x12 + { + size, err := m.BlockMeta.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintV1(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *TenantIndex) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TenantIndex) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TenantIndex) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.CompactedMeta) > 0 { + for iNdEx := len(m.CompactedMeta) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.CompactedMeta[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintV1(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.Meta) > 0 { + for iNdEx := len(m.Meta) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Meta[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintV1(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + n5, err5 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt):]) + if err5 != nil { + return 0, err5 + } + i -= n5 + i = encodeVarintV1(dAtA, i, uint64(n5)) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintV1(dAtA []byte, offset int, v uint64) int { + offset -= sovV1(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *BlockMeta) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Version) + if l > 0 { + n += 1 + l + sovV1(uint64(l)) + } + l = m.BlockID.Size() + n += 1 + l + sovV1(uint64(l)) + l = len(m.TenantID) + if l > 0 { + n += 1 + l + sovV1(uint64(l)) + } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.StartTime) + n += 1 + l + sovV1(uint64(l)) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.EndTime) + n += 1 + l + sovV1(uint64(l)) + if m.TotalObjects != 0 { + n += 1 + sovV1(uint64(m.TotalObjects)) + } + if m.Size_ != 0 { + n += 1 + sovV1(uint64(m.Size_)) + } + if m.CompactionLevel != 0 { + n += 1 + sovV1(uint64(m.CompactionLevel)) + } + l = m.Encoding.Size() + n += 1 + l + sovV1(uint64(l)) + if m.IndexPageSize != 0 { + n += 1 + sovV1(uint64(m.IndexPageSize)) + } + if m.TotalRecords != 0 { + n += 1 + sovV1(uint64(m.TotalRecords)) + } + l = len(m.DataEncoding) + if l > 0 { + n += 1 + l + sovV1(uint64(l)) + } + if m.BloomShardCount != 0 { + n += 1 + sovV1(uint64(m.BloomShardCount)) + } + if m.FooterSize != 0 { + n += 2 + sovV1(uint64(m.FooterSize)) + } + l = m.DedicatedColumns.Size() + n += 2 + l + sovV1(uint64(l)) + if m.ReplicationFactor != 0 { + n += 2 + sovV1(uint64(m.ReplicationFactor)) + } + return n +} + +func (m *CompactedBlockMeta) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.BlockMeta.Size() + n += 1 + l + sovV1(uint64(l)) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CompactedTime) + n += 1 + l + sovV1(uint64(l)) + return n +} + +func (m *TenantIndex) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt) + n += 1 + l + sovV1(uint64(l)) + if len(m.Meta) > 0 { + for _, e := range m.Meta { + l = e.Size() + n += 1 + l + sovV1(uint64(l)) + } + } + if len(m.CompactedMeta) > 0 { + for _, e := range m.CompactedMeta { + l = e.Size() + n += 1 + l + sovV1(uint64(l)) + } + } + return n +} + +func sovV1(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozV1(x uint64) (n int) { + return sovV1(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *BlockMeta) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: BlockMeta: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: BlockMeta: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthV1 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthV1 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Version = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockID", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthV1 + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthV1 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.BlockID.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TenantID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthV1 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthV1 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TenantID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StartTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthV1 + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthV1 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.StartTime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EndTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthV1 + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthV1 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.EndTime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalObjects", wireType) + } + m.TotalObjects = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalObjects |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Size_", wireType) + } + m.Size_ = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Size_ |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CompactionLevel", wireType) + } + m.CompactionLevel = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CompactionLevel |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Encoding", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthV1 + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthV1 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Encoding.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 12: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IndexPageSize", wireType) + } + m.IndexPageSize = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.IndexPageSize |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 13: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalRecords", wireType) + } + m.TotalRecords = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalRecords |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 14: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DataEncoding", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthV1 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthV1 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DataEncoding = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 15: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field BloomShardCount", wireType) + } + m.BloomShardCount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.BloomShardCount |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 16: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field FooterSize", wireType) + } + m.FooterSize = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.FooterSize |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 17: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DedicatedColumns", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthV1 + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthV1 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.DedicatedColumns.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 18: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ReplicationFactor", wireType) + } + m.ReplicationFactor = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ReplicationFactor |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipV1(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthV1 + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CompactedBlockMeta) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CompactedBlockMeta: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CompactedBlockMeta: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockMeta", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthV1 + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthV1 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.BlockMeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CompactedTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthV1 + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthV1 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.CompactedTime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipV1(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthV1 + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TenantIndex) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TenantIndex: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TenantIndex: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CreatedAt", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthV1 + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthV1 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Meta", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthV1 + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthV1 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Meta = append(m.Meta, &BlockMeta{}) + if err := m.Meta[len(m.Meta)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CompactedMeta", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowV1 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthV1 + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthV1 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CompactedMeta = append(m.CompactedMeta, &CompactedBlockMeta{}) + if err := m.CompactedMeta[len(m.CompactedMeta)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipV1(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthV1 + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipV1(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowV1 + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowV1 + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowV1 + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthV1 + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupV1 + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthV1 + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthV1 = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowV1 = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupV1 = fmt.Errorf("proto: unexpected end of group") +) diff --git a/tempodb/backend/v1/v1.proto b/tempodb/backend/v1/v1.proto index 72d187e0da0..f4be7add048 100644 --- a/tempodb/backend/v1/v1.proto +++ b/tempodb/backend/v1/v1.proto @@ -14,14 +14,14 @@ option (gogoproto.marshaler_all) = true; message BlockMeta { string version = 1[(gogoproto.jsontag) = "format"]; - bytes block_id = 2[(gogoproto.jsontag) = "blockID", (gogoproto.customname) = "BlockID"]; + bytes block_id = 2[(gogoproto.jsontag) = "blockID", (gogoproto.customname) = "BlockID", (gogoproto.customtype) = "github.com/grafana/tempo/pkg/uuid.UUID", (gogoproto.nullable) = false]; string tenant_id = 5[(gogoproto.jsontag) = "tenantID", (gogoproto.customname) = "TenantID"]; google.protobuf.Timestamp start_time = 6[(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = "startTime"]; google.protobuf.Timestamp end_time = 7[(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = "endTime"]; int32 total_objects = 8[(gogoproto.jsontag) = "totalObjects"]; uint64 size = 9; uint32 compaction_level = 10[(gogoproto.jsontag) = "compactionLevel"]; - uint32 encoding = 11; + bytes encoding = 11[(gogoproto.customtype) = "Encoding", (gogoproto.nullable) = false]; uint32 index_page_size = 12[(gogoproto.jsontag) = "indexPageSize"]; uint32 total_records = 13[(gogoproto.jsontag) = "totalRecords"]; string data_encoding = 14[(gogoproto.jsontag) = "dataEncoding"]; From 0395a5b3a6227365cc724f390f9de0ce643f5366 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Tue, 10 Sep 2024 21:54:32 +0000 Subject: [PATCH 10/71] Passing backend tests --- tempodb/backend/raw.go | 17 ++++++++++------- tempodb/backend/raw_test.go | 4 ---- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/tempodb/backend/raw.go b/tempodb/backend/raw.go index 40c46ece5e2..6869ca133b3 100644 --- a/tempodb/backend/raw.go +++ b/tempodb/backend/raw.go @@ -142,18 +142,21 @@ func (w *writer) WriteTenantIndex(ctx context.Context, tenantID string, meta []* return nil } - var ( - b = newTenantIndex(meta, compactedMeta) - buf = &bytes.Buffer{} - ) + b := newTenantIndex(meta, compactedMeta) - err := new(jsonpb.Marshaler).Marshal(buf, b) + // Hmm: the jsonpb call does not seem to respect the Version field on the BlockMeta being written as "format". + // buf = &bytes.Buffer{} + // err := new(jsonpb.Marshaler).Marshal(buf, b) + // if err != nil { + // return err + // } + // indexBytes := buf.Bytes() + + indexBytes, err := json.Marshal(b) if err != nil { return err } - indexBytes := buf.Bytes() - err = w.w.Write(ctx, TenantIndexNameProto, KeyPath([]string{tenantID}), bytes.NewReader(indexBytes), int64(len(indexBytes)), nil) if err != nil { return err diff --git a/tempodb/backend/raw_test.go b/tempodb/backend/raw_test.go index c51d0c58311..b1155d1efe2 100644 --- a/tempodb/backend/raw_test.go +++ b/tempodb/backend/raw_test.go @@ -54,11 +54,7 @@ func TestWriter(t *testing.T) { err = json.Unmarshal(m.writeBuffer, idx) assert.NoError(t, err) - t.Logf("writeBuffer: %v", string(m.writeBuffer)) - - assert.Equal(t, []*BlockMeta{meta}, idx.Meta) assert.True(t, cmp.Equal([]*BlockMeta{meta}, idx.Meta)) // using cmp.Equal to compare json datetimes - assert.Equal(t, []*CompactedBlockMeta(nil), idx.Meta) assert.True(t, cmp.Equal([]*CompactedBlockMeta(nil), idx.CompactedMeta)) // using cmp.Equal to compare json datetimes // When there are no blocks, the tenant index should be deleted From e6cde93598ddec97a1e9e1f564bd3e64380728b6 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 11 Sep 2024 16:01:21 +0000 Subject: [PATCH 11/71] Improve UUID coverage and utility --- pkg/uuid/uuid.go | 27 ++++++++++++++++++++++++++- pkg/uuid/uuid_test.go | 38 +++++++++++++++++++++++++++++++++++--- 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/pkg/uuid/uuid.go b/pkg/uuid/uuid.go index a017e09da29..a62d6eb7513 100644 --- a/pkg/uuid/uuid.go +++ b/pkg/uuid/uuid.go @@ -1,3 +1,6 @@ +// Package uuid provides a UUID type that can be used in protocol buffer +// messages. It only wraps the google/uuid package and implements a couple +// helpers to make creating new instances simpler. package uuid import ( @@ -6,10 +9,32 @@ import ( google_uuid "github.com/google/uuid" ) +var ( + _ json.Unmarshaler = &UUID{} + _ json.Marshaler = &UUID{} +) + type UUID struct { google_uuid.UUID } +func New() UUID { + return UUID{google_uuid.New()} +} + +func MustParse(s string) UUID { + return UUID{google_uuid.MustParse(s)} +} + +func Parse(s string) (UUID, error) { + u, err := google_uuid.Parse(s) + if err != nil { + return UUID{}, err + } + + return UUID{u}, nil +} + func (u UUID) Marshal() ([]byte, error) { return u.MarshalBinary() } @@ -37,7 +62,7 @@ func (u *UUID) Size() int { } func (u UUID) MarshalJSON() ([]byte, error) { - return json.Marshal(u.UUID.String()) + return json.Marshal(u.String()) } func (u *UUID) UnmarshalJSON(data []byte) error { diff --git a/pkg/uuid/uuid_test.go b/pkg/uuid/uuid_test.go index 322d9eecfc0..13f5d7dbf73 100644 --- a/pkg/uuid/uuid_test.go +++ b/pkg/uuid/uuid_test.go @@ -3,17 +3,18 @@ package uuid import ( "testing" - "github.com/google/uuid" + google_uuid "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func Test_roundTrip(t *testing.T) { - u := UUID{uuid.New()} + u := New() t.Logf("u %x", u) require.Equal(t, 16, u.Size()) + // Marshalto b := make([]byte, 16) l, err := u.MarshalTo(b) require.NoError(t, err) @@ -22,7 +23,38 @@ func Test_roundTrip(t *testing.T) { u2 := UUID{} err = u2.Unmarshal(b) - t.Logf("u2 %x", u2) require.NoError(t, err) assert.Equal(t, u.UUID, u2.UUID) + + // Marshal + b2, err := u2.Marshal() + require.NoError(t, err) + require.Equal(t, 16, len(b2)) + + u3 := UUID{} + err = u3.Unmarshal(b2) + require.NoError(t, err) + assert.Equal(t, u.UUID, u2.UUID, u3.UUID) + + // MarshalJSON + b3, err := u3.MarshalJSON() + require.NoError(t, err) + + u4 := UUID{} + err = u4.UnmarshalJSON(b3) + require.NoError(t, err) + assert.Equal(t, u.UUID, u2.UUID, u3.UUID, u4.UUID) +} + +func Test_helpers(t *testing.T) { + u := google_uuid.New() + s := MustParse(u.String()) + require.Equal(t, u, s.UUID) + + s2, err := Parse(u.String()) + require.NoError(t, err) + require.Equal(t, u, s2.UUID) + + _, err = Parse("x") + require.Error(t, err) } From abaaac418785b90ecf4c91440273d08a9f74cc4f Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 11 Sep 2024 16:40:21 +0000 Subject: [PATCH 12/71] TempoDB updates for UUID and struct type changes --- tempodb/backend/local/local_test.go | 25 +- tempodb/backend/raw.go | 66 +- tempodb/backend/raw_test.go | 25 +- tempodb/backend/tenantindex_benchmark_test.go | 87 + tempodb/backend/test/benchmark_test.go | 57 + tempodb/backend/testdata/test/index | 2002 +++++++++++++++++ tempodb/backend/testdata/test/index.json.gz | Bin 0 -> 34699 bytes tempodb/compaction_block_selector.go | 4 +- tempodb/compaction_block_selector_test.go | 251 ++- tempodb/compactor.go | 10 +- tempodb/compactor_test.go | 29 +- tempodb/encoding/v2/backend_block.go | 2 +- tempodb/encoding/v2/backend_block_test.go | 2 +- tempodb/encoding/v2/block.go | 14 +- tempodb/encoding/v2/compactor.go | 10 +- tempodb/encoding/v2/create_block.go | 2 +- tempodb/encoding/v2/streaming_block.go | 4 +- tempodb/encoding/v2/streaming_block_test.go | 12 +- tempodb/encoding/v2/wal_block.go | 4 +- .../encoding/vparquet2/block_findtracebyid.go | 6 +- .../vparquet2/block_findtracebyid_test.go | 2 +- tempodb/encoding/vparquet2/block_iterator.go | 4 +- .../encoding/vparquet2/block_iterator_test.go | 2 +- tempodb/encoding/vparquet2/block_search.go | 10 +- .../encoding/vparquet2/block_search_tags.go | 4 +- tempodb/encoding/vparquet2/compactor.go | 19 +- tempodb/encoding/vparquet2/compactor_test.go | 7 +- tempodb/encoding/vparquet2/copy.go | 12 +- tempodb/encoding/vparquet2/create.go | 12 +- tempodb/encoding/vparquet2/readers.go | 4 +- tempodb/encoding/vparquet2/readers_test.go | 2 +- .../encoding/vparquet3/block_findtracebyid.go | 6 +- .../vparquet3/block_findtracebyid_test.go | 2 +- tempodb/encoding/vparquet3/block_iterator.go | 4 +- .../encoding/vparquet3/block_iterator_test.go | 2 +- tempodb/encoding/vparquet3/block_search.go | 6 +- .../encoding/vparquet3/block_search_tags.go | 4 +- tempodb/encoding/vparquet3/compactor.go | 21 +- tempodb/encoding/vparquet3/compactor_test.go | 13 +- tempodb/encoding/vparquet3/copy.go | 12 +- tempodb/encoding/vparquet3/create.go | 12 +- tempodb/encoding/vparquet3/readers.go | 2 +- tempodb/encoding/vparquet3/readers_test.go | 2 +- .../encoding/vparquet4/block_findtracebyid.go | 6 +- .../vparquet4/block_findtracebyid_test.go | 2 +- tempodb/encoding/vparquet4/block_iterator.go | 4 +- .../encoding/vparquet4/block_iterator_test.go | 2 +- tempodb/encoding/vparquet4/block_search.go | 6 +- .../encoding/vparquet4/block_search_tags.go | 4 +- tempodb/encoding/vparquet4/compactor.go | 11 +- tempodb/encoding/vparquet4/compactor_test.go | 13 +- tempodb/encoding/vparquet4/copy.go | 12 +- tempodb/encoding/vparquet4/create.go | 12 +- tempodb/encoding/vparquet4/readers.go | 2 +- tempodb/encoding/vparquet4/readers_test.go | 2 +- tempodb/retention.go | 4 +- tempodb/retention_test.go | 13 +- tempodb/tempodb.go | 2 +- tempodb/tempodb_search_test.go | 11 +- tempodb/tempodb_test.go | 83 +- 60 files changed, 2547 insertions(+), 418 deletions(-) create mode 100644 tempodb/backend/tenantindex_benchmark_test.go create mode 100644 tempodb/backend/test/benchmark_test.go create mode 100644 tempodb/backend/testdata/test/index create mode 100644 tempodb/backend/testdata/test/index.json.gz diff --git a/tempodb/backend/local/local_test.go b/tempodb/backend/local/local_test.go index ab7d1bb255e..4eb125471cb 100644 --- a/tempodb/backend/local/local_test.go +++ b/tempodb/backend/local/local_test.go @@ -11,10 +11,10 @@ import ( "github.com/grafana/tempo/pkg/io" - "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" ) @@ -38,7 +38,7 @@ func TestReadWrite(t *testing.T) { } fakeMeta := &backend.BlockMeta{ - BlockId: []byte(blockID.String()), + BlockID: blockID, } fakeObject := make([]byte, 20) @@ -46,29 +46,26 @@ func TestReadWrite(t *testing.T) { _, err = crand.Read(fakeObject) assert.NoError(t, err, "unexpected error creating fakeObject") - blockID, err = uuid.ParseBytes(fakeMeta.BlockId) - assert.NoError(t, err, "unexpected error parsing blockID") - ctx := context.Background() for _, id := range tenantIDs { - fakeMeta.TenantId = id - err = w.Write(ctx, objectName, backend.KeyPathForBlock(blockID, id), bytes.NewReader(fakeObject), int64(len(fakeObject)), nil) + fakeMeta.TenantID = id + err = w.Write(ctx, objectName, backend.KeyPathForBlock(fakeMeta.BlockID.UUID, id), bytes.NewReader(fakeObject), int64(len(fakeObject)), nil) assert.NoError(t, err, "unexpected error writing") - err = w.Write(ctx, backend.MetaName, backend.KeyPathForBlock(blockID, id), bytes.NewReader(fakeObject), int64(len(fakeObject)), nil) + err = w.Write(ctx, backend.MetaName, backend.KeyPathForBlock(fakeMeta.BlockID.UUID, id), bytes.NewReader(fakeObject), int64(len(fakeObject)), nil) assert.NoError(t, err, "unexpected error meta.json") - err = w.Write(ctx, backend.CompactedMetaName, backend.KeyPathForBlock(blockID, id), bytes.NewReader(fakeObject), int64(len(fakeObject)), nil) + err = w.Write(ctx, backend.CompactedMetaName, backend.KeyPathForBlock(fakeMeta.BlockID.UUID, 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) + actualObject, size, err := r.Read(ctx, objectName, backend.KeyPathForBlock(blockID.UUID, 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) + err = r.ReadRange(ctx, objectName, backend.KeyPathForBlock(blockID.UUID, tenantIDs[0]), 5, actualReadRange, nil) assert.NoError(t, err, "unexpected error range") assert.Equal(t, fakeObject[5:10], actualReadRange) @@ -95,7 +92,7 @@ func TestShutdownLeavesTenantsWithBlocks(t *testing.T) { tenant := "fake" // write a "block" - err = w.Write(ctx, "test", backend.KeyPathForBlock(blockID, tenant), contents, contents.Size(), nil) + err = w.Write(ctx, "test", backend.KeyPathForBlock(blockID.UUID, tenant), contents, contents.Size(), nil) require.NoError(t, err) tenantExists(t, tenant, r) @@ -120,14 +117,14 @@ func TestShutdownRemovesTenantsWithoutBlocks(t *testing.T) { tenant := "tenant" // write a "block" - err = w.Write(ctx, "test", backend.KeyPathForBlock(blockID, tenant), contents, contents.Size(), nil) + err = w.Write(ctx, "test", backend.KeyPathForBlock(blockID.UUID, tenant), contents, contents.Size(), nil) require.NoError(t, err) tenantExists(t, tenant, r) blockExists(t, blockID, tenant, r) // clear the block - err = c.ClearBlock(blockID, tenant) + err = c.ClearBlock(blockID.UUID, tenant) require.NoError(t, err) tenantExists(t, tenant, r) diff --git a/tempodb/backend/raw.go b/tempodb/backend/raw.go index 6869ca133b3..0d3bbaf22ec 100644 --- a/tempodb/backend/raw.go +++ b/tempodb/backend/raw.go @@ -5,12 +5,10 @@ import ( "context" "encoding/json" "errors" - "fmt" "io" "path" "time" - "github.com/gogo/protobuf/jsonpb" google_uuid "github.com/google/uuid" tempo_io "github.com/grafana/tempo/pkg/io" @@ -22,9 +20,6 @@ const ( CompactedMetaName = "meta.compacted.json" TenantIndexName = "index.json.gz" - // Proto - TenantIndexNameProto = "index" - // File name for the cluster seed file. ClusterSeedFileName = "tempo_cluster_seed.json" ) @@ -133,31 +128,17 @@ func (w *writer) WriteTenantIndex(ctx context.Context, tenantID string, meta []* if err != nil && !errors.Is(err, ErrDoesNotExist) { return err } - - err = w.w.Delete(ctx, TenantIndexNameProto, []string{tenantID}, nil) - if err != nil && !errors.Is(err, ErrDoesNotExist) { - return err - } - return nil } b := newTenantIndex(meta, compactedMeta) - // Hmm: the jsonpb call does not seem to respect the Version field on the BlockMeta being written as "format". - // buf = &bytes.Buffer{} - // err := new(jsonpb.Marshaler).Marshal(buf, b) - // if err != nil { - // return err - // } - // indexBytes := buf.Bytes() - - indexBytes, err := json.Marshal(b) + indexBytes, err := b.marshal() if err != nil { return err } - err = w.w.Write(ctx, TenantIndexNameProto, KeyPath([]string{tenantID}), bytes.NewReader(indexBytes), int64(len(indexBytes)), nil) + err = w.w.Write(ctx, TenantIndexName, KeyPath([]string{tenantID}), bytes.NewReader(indexBytes), int64(len(indexBytes)), nil) if err != nil { return err } @@ -223,14 +204,19 @@ func (r *reader) Blocks(ctx context.Context, tenantID string) ([]google_uuid.UUI // BlockMeta implements backend.Reader func (r *reader) BlockMeta(ctx context.Context, blockID google_uuid.UUID, tenantID string) (*BlockMeta, error) { - reader, _, err := r.r.Read(ctx, MetaName, KeyPathForBlock(blockID, tenantID), nil) + reader, size, err := r.r.Read(ctx, MetaName, KeyPathForBlock(blockID, tenantID), nil) if err != nil { return nil, err } defer reader.Close() + bytes, err := tempo_io.ReadAllWithEstimate(reader, size) + if err != nil { + return nil, err + } + out := &BlockMeta{} - err = jsonpb.Unmarshal(reader, out) + err = json.Unmarshal(bytes, out) if err != nil { return nil, err } @@ -240,12 +226,25 @@ func (r *reader) BlockMeta(ctx context.Context, blockID google_uuid.UUID, tenant // TenantIndex implements backend.Reader func (r *reader) TenantIndex(ctx context.Context, tenantID string) (*TenantIndex, error) { - tenantIndex, err := r.tenantIndexProto(ctx, tenantID) + reader, size, err := r.r.Read(ctx, TenantIndexName, KeyPath([]string{tenantID}), nil) if err != nil { return nil, err } - return tenantIndex, nil + defer reader.Close() + + bytes, err := tempo_io.ReadAllWithEstimate(reader, size) + if err != nil { + return nil, err + } + + i := &TenantIndex{} + err = i.unmarshal(bytes) + if err != nil { + return nil, err + } + + return i, nil } // Find implements backend.Reader @@ -258,23 +257,6 @@ func (r *reader) Shutdown() { r.r.Shutdown() } -func (r *reader) tenantIndexProto(ctx context.Context, tenantID string) (*TenantIndex, error) { - tenantIndexMessage := &TenantIndex{} - - reader, _, err := r.r.Read(ctx, TenantIndexNameProto, KeyPath([]string{tenantID}), nil) - if err != nil { - return nil, err - } - defer reader.Close() - - err = jsonpb.Unmarshal(reader, tenantIndexMessage) - if err == nil { - return tenantIndexMessage, nil - } - - return nil, fmt.Errorf("error reading tenant index proto: %w", err) -} - // KeyPathForBlock returns a correctly ordered keypath given a block id and tenantid func KeyPathForBlock(blockID google_uuid.UUID, tenantID string) KeyPath { return []string{tenantID, blockID.String()} diff --git a/tempodb/backend/raw_test.go b/tempodb/backend/raw_test.go index b1155d1efe2..a5e959296b5 100644 --- a/tempodb/backend/raw_test.go +++ b/tempodb/backend/raw_test.go @@ -1,12 +1,10 @@ package backend import ( - "bytes" "context" "encoding/json" "testing" - "github.com/gogo/protobuf/jsonpb" "github.com/google/go-cmp/cmp" "github.com/google/uuid" "github.com/stretchr/testify/assert" @@ -37,9 +35,6 @@ func TestWriter(t *testing.T) { assert.NoError(t, err) assert.True(t, m.closeAppendCalled) - // TODO: we want to check the json marshaling will unmarshal with jsonpb. - // TODO: we also want to check that we can round-trip with jsonpb. - meta := NewBlockMeta("test", uuid.New(), "blerg", EncGZIP, "glarg") expected, err = json.Marshal(meta) assert.NoError(t, err) @@ -51,7 +46,7 @@ func TestWriter(t *testing.T) { assert.NoError(t, err) idx := &TenantIndex{} - err = json.Unmarshal(m.writeBuffer, idx) + err = idx.unmarshal(m.writeBuffer) assert.NoError(t, err) assert.True(t, cmp.Equal([]*BlockMeta{meta}, idx.Meta)) // using cmp.Equal to compare json datetimes @@ -63,7 +58,7 @@ func TestWriter(t *testing.T) { err = w.WriteTenantIndex(ctx, "test", nil, nil) assert.NoError(t, err) - expectedDeleteMap := map[string]map[string]int{TenantIndexName: {"test": 1}, TenantIndexNameProto: {"test": 1}} + expectedDeleteMap := map[string]map[string]int{TenantIndexName: {"test": 1}} assert.Equal(t, expectedDeleteMap, w.(*writer).w.(*MockRawWriter).deleteCalls) // When a backend returns ErrDoesNotExist, the tenant index should be deleted, but no error should be returned if the tenant index does not exist @@ -114,15 +109,7 @@ func TestReader(t *testing.T) { assert.Nil(t, meta) expectedMeta := NewBlockMeta("test", uuid.New(), "blerg", EncGZIP, "glarg") - - var ( - bb = []byte{} - buf = bytes.NewBuffer(bb) - ) - err = new(jsonpb.Marshaler).Marshal(buf, expectedMeta) - assert.NoError(t, err) - m.R = buf.Bytes() - t.Logf("meta: %v", string(m.R)) + m.R, _ = json.Marshal(expectedMeta) meta, err = r.BlockMeta(ctx, uuid.New(), "test") assert.NoError(t, err) assert.Equal(t, expectedMeta, meta) @@ -131,6 +118,12 @@ func TestReader(t *testing.T) { idx, err := r.TenantIndex(ctx, "test") assert.Error(t, err) assert.Nil(t, idx) + + expectedIdx := newTenantIndex([]*BlockMeta{expectedMeta}, nil) + m.R, _ = expectedIdx.marshal() + idx, err = r.TenantIndex(ctx, "test") + assert.NoError(t, err) + assert.True(t, cmp.Equal(expectedIdx, idx)) } func TestKeyPathForBlock(t *testing.T) { diff --git a/tempodb/backend/tenantindex_benchmark_test.go b/tempodb/backend/tenantindex_benchmark_test.go new file mode 100644 index 00000000000..1a48d82caa5 --- /dev/null +++ b/tempodb/backend/tenantindex_benchmark_test.go @@ -0,0 +1,87 @@ +package backend + +import ( + "testing" + "time" + + "github.com/google/uuid" + "github.com/stretchr/testify/require" +) + +func BenchmarkIndexMarshal(b *testing.B) { + idx := &TenantIndex{ + Meta: []*BlockMeta{ + NewBlockMeta("test", uuid.New(), "v1", EncGZIP, "adsf"), + NewBlockMeta("test", uuid.New(), "v2", EncNone, "adsf"), + NewBlockMeta("test", uuid.New(), "v3", EncLZ4_4M, "adsf"), + }, + CompactedMeta: []*CompactedBlockMeta{ + { + BlockMeta: *NewBlockMeta("test", uuid.New(), "v1", EncGZIP, "adsf"), + CompactedTime: time.Now(), + }, + { + BlockMeta: *NewBlockMeta("test", uuid.New(), "v1", EncZstd, "adsf"), + CompactedTime: time.Now(), + }, + { + BlockMeta: *NewBlockMeta("test", uuid.New(), "v1", EncSnappy, "adsf"), + CompactedTime: time.Now(), + }, + }, + } + + for i := range idx.Meta { + idx.Meta[i].DedicatedColumns = DedicatedColumns{ + {Scope: "resource", Name: "namespace", Type: "string"}, + {Scope: "span", Name: "http.method", Type: "string"}, + {Scope: "span", Name: "namespace", Type: "string"}, + } + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _ = idx.marshal() + } +} + +func BenchmarkIndexUnmarshal(b *testing.B) { + idx := &TenantIndex{ + Meta: []*BlockMeta{ + NewBlockMeta("test", uuid.New(), "v1", EncGZIP, "adsf"), + NewBlockMeta("test", uuid.New(), "v2", EncNone, "adsf"), + NewBlockMeta("test", uuid.New(), "v3", EncLZ4_4M, "adsf"), + }, + CompactedMeta: []*CompactedBlockMeta{ + { + BlockMeta: *NewBlockMeta("test", uuid.New(), "v1", EncGZIP, "adsf"), + CompactedTime: time.Now(), + }, + { + BlockMeta: *NewBlockMeta("test", uuid.New(), "v1", EncZstd, "adsf"), + CompactedTime: time.Now(), + }, + { + BlockMeta: *NewBlockMeta("test", uuid.New(), "v1", EncSnappy, "adsf"), + CompactedTime: time.Now(), + }, + }, + } + + for i := range idx.Meta { + idx.Meta[i].DedicatedColumns = DedicatedColumns{ + {Scope: "resource", Name: "namespace", Type: "string"}, + {Scope: "span", Name: "http.method", Type: "string"}, + {Scope: "span", Name: "namespace", Type: "string"}, + } + } + + buf, err := idx.marshal() + require.NoError(b, err) + + unIdx := &TenantIndex{} + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = unIdx.unmarshal(buf) + } +} diff --git a/tempodb/backend/test/benchmark_test.go b/tempodb/backend/test/benchmark_test.go new file mode 100644 index 00000000000..9b0ad5af703 --- /dev/null +++ b/tempodb/backend/test/benchmark_test.go @@ -0,0 +1,57 @@ +package test + +import ( + "context" + "testing" + "time" + + "github.com/grafana/tempo/pkg/uuid" + "github.com/grafana/tempo/tempodb/backend" + "github.com/grafana/tempo/tempodb/backend/local" + "github.com/stretchr/testify/require" +) + +func BenchmarkIndexLoad(b *testing.B) { + ctx := context.Background() + tenant := "test" + + blockMeta := make([]*backend.BlockMeta, 1000) + for i := range len(blockMeta) { + blockMeta[i] = &backend.BlockMeta{ + Version: "vParquet3", + BlockID: uuid.New(), + TenantID: tenant, + StartTime: time.Now().Add(-50 * time.Minute), + EndTime: time.Now().Add(-40 * time.Minute), + TotalObjects: 10, + Size_: 12345, + CompactionLevel: 1, + Encoding: backend.EncZstd, + IndexPageSize: 250000, + TotalRecords: 124356, + DataEncoding: "", + BloomShardCount: 244, + FooterSize: 15775, + DedicatedColumns: backend.DedicatedColumns{ + {Scope: "resource", Name: "namespace", Type: "string"}, + {Scope: "span", Name: "http.method", Type: "string"}, + {Scope: "span", Name: "namespace", Type: "string"}, + }, + } + } + + rr, rw, _, err := local.New(&local.Config{ + Path: "/home/zach/go/src/github.com/grafana/tempo/tempodb/backend/testdata", + }) + require.NoError(b, err) + + w := backend.NewWriter(rw) + w.WriteTenantIndex(ctx, tenant, blockMeta, nil) + + r := backend.NewReader(rr) + b.ResetTimer() + + for i := 0; i < b.N; i++ { + r.TenantIndex(ctx, tenant) + } +} diff --git a/tempodb/backend/testdata/test/index b/tempodb/backend/testdata/test/index new file mode 100644 index 00000000000..6dc003daa99 --- /dev/null +++ b/tempodb/backend/testdata/test/index @@ -0,0 +1,2002 @@ + + Ýîæ¶ÁûŸ— + vParquet3$34720b7f-8c2f-4fbc-b53c-499cd909b578*test2 ¥×涌Œâ: ýÛ涻â@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$31c15d8f-29a1-4efc-bd71-3add16c07a4d*test2 ¥×涷Ÿâ: ýÛ涛 â@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e3095ecc-26e2-4b6e-844e-04025a003af4*test2 ¥×æ¶ߨâ: ýÛæ¶Í©â@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$bee6737a-b2c5-44d8-8d35-48e4a5a63612*test2 ¥×涣±â: ýÛ涇²â@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e1a7cd52-24bb-4433-acfe-214bd847ab7f*test2 ¥×涵¹â: ýÛ涅ºâ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$fb22fa11-019b-4dc7-881b-b5d01ed6c212*test2 ¥×涩Áâ: ýÛæ¶ùÁâ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ad2333d5-e11f-459e-8b1e-67307545ee88*test2 ¥×涉Éâ: ýÛæ¶ÙÉâ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$dfef4b73-79f9-4396-946c-51bfb501552b*test2 ¥×æ¶óÐâ: ýÛæ¶ÃÑâ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ac19147c-7007-427f-8d08-5ffacb8e9f1e*test2 ¥×æ¶ÝØâ: ýÛ涭Ùâ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1f9f58e5-ee36-4e54-8072-854e89ec5e19*test2 ¥×æ¶Çàâ: ýÛ涗áâ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ced31351-601c-49d8-a6ee-8b3ae42e407f*test2 ¥×涺èâ: ýÛ涋éâ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c73c64d5-00de-40d0-b20d-a773f4c8b40e*test2 ¥×涮ðâ: ýÛæ¶ÿðâ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$fc1c0b47-f948-4127-9015-344ce8d3dfdf*test2 ¥×涎øâ: ýÛæ¶Þøâ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9d55b08c-4d37-4f40-baa8-15caa8332707*test2 ¥×æ¶Úÿâ: ýÛ涪€ã@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$561c627a-0f2f-47c9-b3c7-d921001f80e4*test2 ¥×涒‡ã: ýÛæ¶â‡ã@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$fb058b64-a45b-48f4-818f-29e02c069196*test2 ¥×æ¶ÔŽã: ýÛ涤ã@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b8119ad7-b2fa-4041-a990-4da77bdb56c4*test2 ¥×涋–ã: ýÛæ¶Ü–ã@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3d3f7c43-a93b-4a89-aa00-86cb500da444*test2 ¥×æ¶Íã: ýÛ涞ã@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$54e63648-5881-41b3-98e7-58732ae86459*test2 ¥×涥ã: ýÛæ¶ߥã@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$36f99eec-c55b-40bc-9c43-fc3ab5b6a5e7*test2 ¥×æ¶å¬ã: ýÛ涿­ã@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ef1f6fb5-0cac-4fdc-a00c-abdf8e472afa*test2 ¥×涱´ã: ýÛ涋µã@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$caf37dbc-459c-42db-9a15-fd255e0bcaa8*test2 ¥×æ¶ͼã: ýÛ涽ã@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$bac9a9b6-6e1f-4b1a-8947-1dd04f4190de*test2 ¥×涘Äã: ýÛæ¶éÄã@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$fd643b61-9066-4cad-b6d8-37ab3545ce95*test2 ¥×æ¶ÐËã: ýÛ涠Ìã@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$50a815b8-7cf9-4520-9c2b-9e5460e2c6f6*test2 ¥×消Óã: ýÛæ¶ØÓã@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e1ddca66-6f4c-4e2d-94b3-c1ad5439dd85*test2 ¥×æ¶ÀÚã: ýÛæ¶Ûã@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ce93ddd8-78d2-455f-9e87-477b152f95d8*test2 ¥×涬ãã: ýÛ涆äã@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6a189456-eddc-4169-9952-8dbede01d10a*test2 ¥×æ¶øêã: ýÛæ¶Èëã@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$52e3b0e6-66ad-42ff-b915-143a68010110*test2 ¥×涯òã: ýÛ涀óã@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9df7a052-02e3-4bad-85fd-e67312ba0ca2*test2 ¥×涷úã: ýÛ消ûã@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9b1227ce-ce23-48ce-8616-d8b9e9c1f834*test2 ¥×æ¶ïä: ýÛ涿‚ä@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$50feaff7-4109-4f8e-b7bd-7305617a11a7*test2 ¥×涉ä: ýÛæ¶÷‰ä@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2985f736-db81-4619-b9f1-81ce7f095def*test2 ¥×æ¶éä: ýÛæ¶Ñä@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$33b1f492-9821-4cbb-9295-e6664e0513e7*test2 ¥×æ¶ɘä: ýÛ涙™ä@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5451e9f3-5f8c-48e5-b1aa-4a222ac96cc0*test2 ¥×涞 ä: ýÛæ¶ï ä@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$73a33d51-1c37-445c-bfb0-b0cbe3e4b7f4*test2 ¥×æ¶à§ä: ýÛ涺¨ä@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2932cda4-dafa-4f22-bc97-b5b775972cb0*test2 ¥×涘¯ä: ýÛæ¶è¯ä@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b1469f50-252a-4d62-8297-c05535efa1db*test2 ¥×涌·ä: ýÛæ¶Ü·ä@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b1fd861d-be76-4bc1-91da-9c302736d1ee*test2 ¥×æ¶â¾ä: ýÛ涼¿ä@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$23f8fa00-914c-481e-a24d-e6f6aba33a0e*test2 ¥×涚Æä: ýÛæ¶êÆä@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6ce33700-086c-4bfb-8a45-debcbe585031*test2 ¥×涡Îä: ýÛæ¶òÎä@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6479ff52-a337-4b8b-b2d6-51a1cb9628d2*test2 ¥×æ¶ÏÕä: ýÛ涟Öä@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$951f3c57-30ee-42dd-b0d9-720e5ba57ec1*test2 ¥×润âä: ýÛæ¶öâä@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9f58bb61-5e98-4d1b-8c60-c2f29d502743*test2 ¥×涤êä: ýÛæ¶þêä@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$403532b3-7a22-494d-a0ae-682649622fa0*test2 ¥×æ¶úñä: ýÛæ¶Êòä@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c1dd26be-56f7-46f4-b536-95a8b89079f6*test2 ¥×液ùä: ýÛ涂úä@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8fd10354-c85d-402b-832d-07120b3e4500*test2 ¥×涒å: ýÛæ¶ìå@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$fef9a88a-40e6-4115-b51a-a8df20f68f53*test2 ¥×æ¶݈å: ýÛ涸‰å@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7a4a0523-b1b9-4c7f-b749-041cffe7be81*test2 ¥×涩å: ýÛæ¶ùå@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$eb4ff860-0d43-44ce-954c-406dcb415820*test2 ¥×æ¶á—å: ýÛ涱˜å@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7e5693ee-b3c3-45e7-997f-193556e0c736*test2 ¥×涙Ÿå: ýÛæ¶éŸå@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$66995a97-e38d-42ff-a8ee-bbc0b9774338*test2 ¥×涗§å: ýÛæ¶ç§å@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$41b369c0-0f89-4eec-ba2b-744434df624f*test2 ¥×æ¶Ä®å: ýÛ涟¯å@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$da1b9874-8e64-4653-801a-82ab6b6cb62e*test2 ¥×æ¶à¶å: ýÛ涱·å@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$68c1cf8c-eae9-4ece-a118-3a03ccea00fc*test2 ¥×涗Âå: ýÛæ¶çÂå@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a704d3c9-0ac4-452c-ad05-7e61ce2967f6*test2 ¥×æ¶íÉå: ýÛæ¶ÇÊå@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$94995575-117d-41a2-a7cd-a4c1c44090cd*test2 ¥×æ¶ÍÑå: ýÛæ¶Òå@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$bdf7b014-63c7-439b-925e-944085bf1b3a*test2 ¥×涅Ùå: ýÛæ¶ÕÙå@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b6260feb-c2ac-47ed-a54d-08d6811a24eb*test2 ¥×涃áå: ýÛæ¶Óáå@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d2fae8f1-c005-4867-974e-92ff6b120876*test2 ¥×涳éå: ýÛ涃êå@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$0bca119c-05c4-4cc3-9a0e-420b2e5006b7*test2 ¥×消ñå: ýÛæ¶ãñå@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$18005657-297b-494d-8cd5-8f0caeadc848*test2 ¥×æ¶Êøå: ýÛ涚ùå@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$266478e9-535d-4c5c-ad15-0527ef244ef5*test2 ¥×æ¶Ü€æ: ýÛ涶æ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$41479d7e-e383-4f38-a257-2c6fbee1a32c*test2 ¥×涞ˆæ: ýÛæ¶îˆæ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$514da443-64c9-4e23-9bbb-720462277b56*test2 ¥×æ¶Öæ: ýÛ润æ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$353f15ee-a8bc-4372-9770-169af16fa889*test2 ¥×涶—æ: ýÛ涆˜æ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$62525a0c-e2d9-4dc9-9b99-51c3d02495a3*test2 ¥×涕Ÿæ: ýÛæ¶æŸæ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ea400fe5-8691-40ea-9650-7da19be0d697*test2 ¥×涉§æ: ýÛæ¶Ù§æ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2f9abb23-e6d4-4ac5-b7b2-6e48757356d8*test2 ¥×æ¶Á®æ: ýÛ涑¯æ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2ebe1621-b602-4fda-81d4-c7280c077a10*test2 ¥×涗¶æ: ýÛæ¶ç¶æ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8ea7e560-2a79-4cdc-815a-405fbaf9e880*test2 ¥×æ¶í½æ: ýÛæ¶Ǿæ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1c4f624d-c283-41e2-8a55-db0321cec342*test2 ¥×涯Åæ: ýÛæ¶ÿÅæ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3e177449-bf40-4150-9b5d-2081e567cab6*test2 ¥×涄Íæ: ýÛæ¶ÕÍæ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$75c233c5-4d9e-416f-9d74-e4d90346a462*test2 ¥×æ¶ÚÔæ: ýÛ涪Õæ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$df160e2f-23f5-4c6e-b924-534df4a56877*test2 ¥×涒Üæ: ýÛæ¶âÜæ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b5c4dbc4-f289-4d64-91d2-d1400c3f308c*test2 ¥×æ¶òãæ: ýÛæ¶Âäæ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$51c033e4-0d7f-44cb-9c5b-c2ada8d74043*test2 ¥×涎ìæ: ýÛæ¶Þìæ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$602f388a-249e-41cb-bb11-e8bba3c62c89*test2 ¥×æ¶Ðóæ: ýÛ涠ôæ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$29ee80ac-a1e6-45b9-81c8-8bdbc2810e51*test2 ¥×涥ûæ: ýÛæ¶öûæ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c6c56e88-a550-4d4d-9dbf-3d1c7abc8f47*test2 ¥×æ¶Ý‚ç: ýÛ涭ƒç@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c39276f6-fd79-443c-b140-7bad86ced341*test2 ¥×涳Šç: ýÛ涃‹ç@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$010f5f8f-499e-4d36-9f20-64f93830b45c*test2 ¥×æ¶ë‘ç: ýÛæ¶Å’ç@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a6205b2a-33e6-4db1-a972-a0698f0c2a35*test2 ¥×涭™ç: ýÛæ¶ý™ç@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ed7020fd-b318-4563-bf03-b1c54e3a3be7*test2 ¥×涄¦ç: ýÛæ¶Ô¦ç@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$43d9ffa6-bc65-4273-b801-a292d32a48a5*test2 ¥×涠®ç: ýÛæ¶ð®ç@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e8f2cadb-035c-4cfa-9cb3-ba1bc6b5d1ca*test2 ¥×涔¶ç: ýÛæ¶ä¶ç@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a118d311-6182-46d5-87ef-43a493baf613*test2 ¥×æ¶ý½ç: ýÛæ¶ξç@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$231111c2-95e2-462a-bf1b-4babc6798475*test2 ¥×æ¶çÅç: ýÛ涷Æç@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7d59300b-db54-4d75-ab12-a070d4ad4c7c*test2 ¥×涽Íç: ýÛæ¶Îç@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$13805541-f5c2-4825-ae26-c80ea35e87c9*test2 ¥×æ¶ÿÔç: ýÛæ¶ÏÕç@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a5b38f46-467c-49c2-a53f-b1ef2878fbe0*test2 ¥×æ¶ËÜç: ýÛ涛Ýç@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$421eca60-80f6-4898-95fc-473ef36ae593*test2 ¥×æ¶äç: ýÛæ¶çäç@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$40bd5c70-563a-4c9d-a9dd-762822fae484*test2 ¥×æ¶Äëç: ýÛ涞ìç@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$158feb8e-6d7c-435d-bceb-1540155b799e*test2 ¥×涚óç: ýÛæ¶êóç@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6e7c40b7-78f1-4d97-be41-d3cd876ea95f*test2 ¥×æ¶æúç: ýÛ涶ûç@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$756294b2-3838-40ee-82c9-7e7d57bb1296*test2 ¥×涞‚è: ýÛæ¶ø‚è@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$43f691c2-c027-465f-8dee-e8de680442f0*test2 ¥×æ¶à‰è: ýÛ涺Šè@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4f18a16f-e3c5-47f1-b588-ce09ea5bb58e*test2 ¥×涡‘è: ýÛæ¶ò‘è@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3af88d67-2543-495f-92c4-36c29205ee5d*test2 ¥×æ¶Ù˜è: ýÛ涩™è@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$31a06c0d-df78-4ca9-80f9-8c49941e97c3*test2 ¥×涥 è: ýÛæ¶õ è@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f89aca7a-2535-4eb5-80e9-140e8e738db5*test2 ¥×æ¶ݧè: ýÛ涭¨è@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$cb6333c1-5ba0-4a64-a774-23503890f8ff*test2 ¥×æ¶ǯè: ýÛ涗°è@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$755179a2-a3a1-4854-a971-a2d1fef880d5*test2 ¥×æ¶þ¶è: ýÛæ¶Ï·è@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a2f12024-e18a-48c5-b051-82a60c802781*test2 ¥×涶¾è: ýÛ涿è@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3426e3da-d905-4315-ac20-f9f47de38ced*test2 ¥×涱Éè: ýÛ涋Êè@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2806868e-1b39-4d78-ad60-a20536c797e1*test2 ¥×æ¶ýÐè: ýÛæ¶ÍÑè@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a09118e3-5759-4972-9482-64c70b6f65c6*test2 ¥×æ¶ÈØè: ýÛ涙Ùè@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$462f3253-aa3e-492c-8daf-f7988c298646*test2 ¥×涨àè: ýÛæ¶øàè@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a6bf17a8-685e-4973-b141-9b34344f6baa*test2 ¥×æ¶àçè: ýÛ涰èè@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$66170d47-aac4-410e-b7b8-34d3217483b8*test2 ¥×涬ïè: ýÛæ¶üïè@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$81e356b9-8be3-4daa-bbc9-9d832d06b202*test2 ¥×æ¶äöè: ýÛ涴÷è@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8a4f2ff3-684c-40dd-babd-b59a4753b373*test2 ¥×涹þè: ýÛ涊ÿè@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$607194d9-affb-488d-bef7-50c66ed270f5*test2 ¥×æ¶û…é: ýÛæ¶Õ†é@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$468a9d6c-83f3-4807-98ac-b93380ac0708*test2 ¥×æ¶åé: ýÛ涵Žé@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d3554b4e-f70f-4096-a281-f09bf8820ec2*test2 ¥×涱•é: ýÛ涖é@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$77896dd7-8b1c-41f5-953d-2b5c3fd0251d*test2 ¥×æ¶óœé: ýÛæ¶Ãé@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$116033fd-1d93-491b-bb4e-35e56b498ca9*test2 ¥×涫¤é: ýÛæ¶û¤é@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$21fd3dcd-eaa1-47dd-a428-195f1d661a53*test2 ¥×涀¬é: ýÛæ¶Ѭé@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6ca4b681-1fee-4976-8305-1e26d23d318f*test2 ¥×涳é: ýÛ涒´é@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6cb9bd7c-1f74-4a2f-a370-fa28f4731f5f*test2 ¥×涄»é: ýÛæ¶Ô»é@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$99021a98-0037-4776-aa04-10d92ae2f3f2*test2 ¥×æ¶ÐÂé: ýÛ涠Ãé@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9fbeab06-a37d-4db0-9736-d93ab1a4fccd*test2 ¥×涜Êé: ýÛæ¶ìÊé@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2be66218-eada-43f0-92a0-c5149da88b6e*test2 ¥×æ¶ÝÑé: ýÛ涮Òé@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6d544a8e-8e9b-4794-80b6-4cb49397d373*test2 ¥×涟Ùé: ýÛæ¶ùÙé@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3e9c9edc-34fd-43b9-943e-3db4b89653a6*test2 ¥×æ¶×àé: ýÛ涱áé@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$873bd081-45cb-4ccf-9b98-aa9a680c8643*test2 ¥×涪ëé: ýÛæ¶úëé@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5114e81b-6dad-402a-9af4-616dbb8bbffd*test2 ¥×æ¶ëòé: ýÛ涻óé@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7e786eaf-5958-41b9-977b-fe71ae2c69e7*test2 ¥×æ¶Áúé: ýÛ涑ûé@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8486bc15-28c4-46d8-af63-0821ea450901*test2 ¥×涂ê: ýÛæ¶Ý‚ê@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$48726622-0d4e-4f23-9f09-c02257087db4*test2 ¥×æ¶Ù‰ê: ýÛ涩Šê@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$916d0693-ed16-489b-940a-6ed7d9ee4655*test2 ¥×涥‘ê: ýÛæ¶õ‘ê@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$87bb77ac-2810-4c25-9824-321ba5d63fb5*test2 ¥×æ¶ð˜ê: ýÛæ¶Á™ê@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$320d1373-5c50-41bd-8432-cca26954d1d2*test2 ¥×涼 ê: ýÛ涖¡ê@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9bbab5e7-07c7-4524-9f05-58b3cd9d5efb*test2 ¥×æ¶þ§ê: ýÛæ¶Ψê@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1946e96f-c580-4657-9340-79362a5b933d*test2 ¥×æ¶À¯ê: ýÛ涰ê@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f825d203-5f0e-40e2-9cf8-1eec15ba5de9*test2 ¥×涌·ê: ýÛæ¶æ·ê@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$073cb9d2-29c1-4274-8294-1c7945772d3e*test2 ¥×æ¶;ê: ýÛ涞¿ê@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8137190c-c943-42a4-a2c7-69d960cccf0e*test2 ¥×涣Æê: ýÛæ¶óÆê@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a0c9d031-81ba-423c-be36-ee44a8c6e09d*test2 ¥×涃Îê: ýÛæ¶ÓÎê@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6193eb17-d554-46ef-983e-5620dce1ca6c*test2 ¥×æ¶÷Õê: ýÛæ¶ÇÖê@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1c9b6fb3-973d-4e5f-af5e-b25e00a30010*test2 ¥×涯Ýê: ýÛ涉Þê@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f7736d5f-8f8e-421d-95db-3866554286db*test2 ¥×æ¶ñäê: ýÛæ¶Áåê@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ba498907-88ae-4358-ac4d-af6911ae5ed3*test2 ¥×涨ìê: ýÛæ¶ùìê@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$46bc6e29-e96f-47c1-a550-c1e53c00bf0e*test2 ¥×涒ôê: ýÛæ¶âôê@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e5c9ab76-687d-4c3a-bcd9-7c79cb147555*test2 ¥×æ¶Êûê: ýÛ涚üê@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$33405d78-a482-4460-923b-9f8347065d4c*test2 ¥×涠ƒë: ýÛæ¶ðƒë@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5de8710f-047e-4058-9400-63af0791d324*test2 ¥×æ¶öŠë: ýÛæ¶Ћë@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$56616ad0-76ae-4814-a972-5af4474f9b05*test2 ¥×æ¶Â’ë: ýÛ涒“ë@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5a94a6fc-0ffe-4134-a12b-710fa996e0eb*test2 ¥×涃šë: ýÛæ¶Óšë@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$11b660a8-fb0a-4758-bda7-f0fc431439f9*test2 ¥×涻¡ë: ýÛ涋¢ë@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$169476af-54ac-40b3-a1ab-dd0f34240303*test2 ¥×涑©ë: ýÛæ¶ë©ë@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6f0a59e1-37ba-4945-aea5-e5b29202f5b1*test2 ¥×æ¶ç°ë: ýÛ涷±ë@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1e07ddbb-f008-4168-9823-07f29e13dd47*test2 ¥×涳¸ë: ýÛ涃¹ë@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$0587f57e-68a4-451c-933e-c6601f1a47ac*test2 ¥×æ¶þ¿ë: ýÛæ¶ÏÀë@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1ffbcc95-8f6d-4d97-ad3f-a43fb328d8da*test2 ¥×æ¶ÊÇë: ýÛ涚Èë@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3461a9fe-48c3-4557-b973-74d136308e16*test2 ¥×涖Ïë: ýÛæ¶æÏë@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a930cc63-741c-4cac-a957-f056637ed90a*test2 ¥×æ¶ÎÖë: ýÛ涞×ë@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$91d2bdfe-163a-43fd-bf09-5f1747d5adf8*test2 ¥×涤Þë: ýÛæ¶ôÞë@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d53fa3d4-edec-4814-99b8-bd9a6e87814f*test2 ¥×æ¶Ûåë: ýÛ涶æë@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5a44bd41-ec78-4f37-b572-463d0fd75a90*test2 ¥×涱íë: ýÛæ¶îë@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$446d586c-03f7-4a37-83c6-8abe6fc2d34b*test2 ¥×æ¶Ü÷ë: ýÛ涶øë@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ee46f138-4876-46af-a9ee-9c47f3b309f5*test2 ¥×涼ÿë: ýÛ涌€ì@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$04800463-a3dc-41af-aae7-5e82db485049*test2 ¥×涇‡ì: ýÛæ¶؇ì@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$48d32234-57d5-4f73-afac-f4307b213004*test2 ¥×æ¶çŽì: ýÛ涷ì@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ecda29db-a867-4aaa-8829-465cb2aa2e85*test2 ¥×涟–ì: ýÛæ¶ï–ì@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f3cb83aa-8386-4fc2-8879-060d81a4cf9f*test2 ¥×æ¶×ì: ýÛ涱žì@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$278802e6-c671-49fb-961f-8a3e153692f6*test2 ¥×涙¥ì: ýÛæ¶é¥ì@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3b688ae4-7842-4e02-bccd-d45de1d7a9f5*test2 ¥×涢²ì: ýÛæ¶ü²ì@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c462bee9-c323-4e6f-80ce-15e6a9000b7d*test2 ¥×涌ºì: ýÛæ¶ܺì@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$aaa9df31-e28d-472e-a0d9-b80bc7be5899*test2 ¥×æ¶ÍÁì: ýÛ涞Âì@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$56b04baf-04f4-4f4b-a47c-5dd4841981eb*test2 ¥×涙Éì: ýÛæ¶éÉì@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f73d20ce-3747-492c-8ba0-870322a9976c*test2 ¥×æ¶åÐì: ýÛ涵Ñì@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$06f7b4dd-02ff-45f9-bab5-681cbc350d85*test2 ¥×涧Øì: ýÛæ¶Ùì@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$0611bd21-3784-4784-b04f-807debf7c118*test2 ¥×æ¶éßì: ýÛ涹àì@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9ca65ffb-295c-4dfa-9c55-fc0e08d81480*test2 ¥×涴çì: ýÛ涅èì@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e4a6b6a7-7035-4f9f-bdcc-80bd0c97c25a*test2 ¥×æ¶ìîì: ýÛ涼ïì@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$bc5fad8b-37c6-49d6-882c-5da975ae2fe5*test2 ¥×涮öì: ýÛæ¶þöì@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4b0781de-10ed-49f0-935c-a0de4b36207a*test2 ¥×涬þì: ýÛæ¶üþì@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e6ce6538-9168-47d5-98e6-46ea30e08448*test2 ¥×æ¶ä…í: ýÛ涴†í@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$69c3df5e-b179-4225-82d7-0e468e163f60*test2 ¥×涰í: ýÛ涀Ží@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$143a95e3-87da-4567-9471-0d6e56bb5b3b*test2 ¥×æ¶ñ”í: ýÛ涕í@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$49fe37d2-1f3b-483f-b66c-50b2b1abe4db*test2 ¥×æ¶ïœí: ýÛ涿í@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$acbf2975-cb7b-4cd4-b46e-a47299b7dc73*test2 ¥×涤í: ýÛæ¶÷¤í@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$df80f848-c9cb-4419-9150-ff7d5d12eeef*test2 ¥×æ¶ß«í: ýÛ涯¬í@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6ccc8495-ad57-4b5a-b7d8-062b303234de*test2 ¥×涫³í: ýÛæ¶û³í@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d9229c7d-0c15-4deb-a900-b8cc497207a8*test2 ¥×æ¶âºí: ýÛ涳»í@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7621c373-b038-4369-ad42-4b4756f22560*test2 ¥×涚Âí: ýÛæ¶ôÂí@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2972f368-ace4-4712-a1d3-86ec3f24e485*test2 ¥×æ¶ðÉí: ýÛæ¶ÊÊí@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$744b429a-ae5e-42bf-9f1f-e7bd7c2f63d9*test2 ¥×æ¶ÆÑí: ýÛ涖Òí@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e3e6814f-55e9-428f-b3a5-5b05779d5dfa*test2 ¥×消Ùí: ýÛæ¶ØÙí@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a957124d-eb50-4475-977b-6966669e4b10*test2 ¥×æ¶èàí: ýÛæ¶Âáí@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3b0fa600-342e-453a-9fcb-b5e2448f780c*test2 ¥×涟èí: ýÛæ¶ùèí@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d4386222-2760-4892-9a0d-4c98d9409e66*test2 ¥×æ¶×ïí: ýÛ涱ðí@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1f5a1a57-1e54-43fe-a5d1-65b0913dfe6b*test2 ¥×涙÷í: ýÛæ¶é÷í@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e374308d-350c-4ffd-9c36-14947c0e6501*test2 ¥×æ¶åþí: ýÛ涵ÿí@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9c07d079-566f-4ca2-944e-da3bd994cffc*test2 ¥×涻†î: ýÛ涋‡î@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d7d44ac7-423c-476e-b1d3-aa0fd9e79c8b*test2 ¥×æ¶òî: ýÛæ¶ÂŽî@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$07bf2959-705d-434f-8739-2a80919448ec*test2 ¥×涴•î: ýÛ涄–î@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$be25d300-59d5-4af7-b69b-fb869aabc628*test2 ¥×æ¶öœî: ýÛæ¶Æî@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2dabe8bd-b80b-4a93-8b20-f117a47e1772*test2 ¥×æ¶̤î: ýÛ涜¥î@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$79a71428-3f81-45b9-8b16-4979b61f8dbd*test2 ¥×æ¶ù«î: ýÛæ¶ʬî@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$89638616-8b90-426c-b460-14a3ad8c32c2*test2 ¥×涱³î: ýÛ涋´î@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9280a0f3-7d28-4315-bdbe-329ad89b2080*test2 ¥×涥»î: ýÛæ¶õ»î@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4fdae1d4-61f9-4c9a-8fb1-e43fe0b9fb08*test2 ¥×æ¶ñÂî: ýÛæ¶ÁÃî@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6ecb45da-632c-45bd-81e8-534e5160d86b*test2 ¥×涩Êî: ýÛæ¶ùÊî@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a8b84f1e-db52-4c16-b469-efeb470e1d9d*test2 ¥×涓Òî: ýÛæ¶íÒî@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9ab2fdf7-e175-4019-b975-90bc1447a5eb*test2 ¥×涛Úî: ýÛæ¶ëÚî@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7600ed2c-9f67-448a-8697-6e7c50553a9e*test2 ¥×æ¶ðáî: ýÛæ¶Ëâî@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$502ff53b-43f3-4beb-8c51-56b53c30e22e*test2 ¥×涨éî: ýÛæ¶øéî@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9ce075e3-71b3-4aa6-8e1a-e72be5a79954*test2 ¥×æ¶óôî: ýÛæ¶Íõî@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$15f1c8d0-a3cd-45bf-8505-85446c28ea27*test2 ¥×涵üî: ýÛ涅ýî@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e88ed253-98fb-409a-9720-19f9a6ccbe73*test2 ¥×涕„ï: ýÛæ¶å„ï@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e6f95454-4504-4341-9a79-9b4c9970491a*test2 ¥×æ¶à‹ï: ýÛ涱Œï@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$cab5c058-f214-4e2a-ab69-c83e1292afe4*test2 ¥×涬“ï: ýÛæ¶ü“ï@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$db58c8df-7af8-4fed-a5de-b2e67cd283ce*test2 ¥×æ¶äšï: ýÛ涴›ï@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f89c533b-1b11-40d6-90eb-651ebbae43e2*test2 ¥×涜¢ï: ýÛæ¶ì¢ï@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5a6a4079-d758-4fa3-97f3-d67d13f32aa9*test2 ¥×æ¶ÕÀï: ýÛ涥Áï@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$10da37f3-130c-46da-b17a-5d056217d61d*test2 ¥×涗Èï: ýÛæ¶ñÈï@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9b32f634-d7d3-454c-a623-2067886292d9*test2 ¥×æ¶ÙÏï: ýÛ涩Ðï@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$dd979cbf-7781-4059-a89b-66c095afe747*test2 ¥×æ¶Ã×ï: ýÛ涓Øï@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$0c589955-200f-4781-90c3-8f2c438861c8*test2 ¥×涎ßï: ýÛæ¶ßßï@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$0c03326d-3d24-4f14-ab60-eeedfba1ca4f*test2 ¥×涂çï: ýÛæ¶Òçï@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$42301477-c393-407e-906a-ab92b876b06f*test2 ¥×涊ïï: ýÛæ¶Úïï@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a1bf6800-3a4d-4d64-b370-3e532f9694b7*test2 ¥×æ¶Ìöï: ýÛ涜÷ï@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1c0bee68-f660-463c-9be9-dcb630cceec5*test2 ¥×涄þï: ýÛæ¶Ôþï@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d23bad90-936d-4959-ae75-601c45c2a04c*test2 ¥×涼…ð: ýÛ涌†ð@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$92c1f597-1f5a-489a-b8dc-ecc82334768c*test2 ¥×涇ð: ýÛæ¶Øð@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$bded5e97-0a2f-4782-a3bf-0908a91c1d27*test2 ¥×æ¶Ó”ð: ýÛ涣•ð@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9556ad45-abe9-4e0f-95a0-6394b2c336ea*test2 ¥×涜ð: ýÛæ¶Ûœð@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e7c4acd0-7b40-469a-a97c-fc1abf845730*test2 ¥×æ¶ãð: ýÛ涓¤ð@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c3bca6e1-94a7-4bbb-9778-e73a9e79d09a*test2 ¥×涣«ð: ýÛæ¶ó«ð@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7d16ca06-bb65-4be5-825a-e29bdc0db855*test2 ¥×æ¶Ú²ð: ýÛ涵³ð@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a553fc2a-5325-4fe2-8cc0-f6edd97bd045*test2 ¥×涒ºð: ýÛæ¶âºð@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$50989ccf-4fbd-4c24-bc0d-7bc11937f99a*test2 ¥×æ¶ÊÁð: ýÛ涚Âð@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b4b2e538-17b0-478a-b67c-5e605a496577*test2 ¥×æ¶øÈð: ýÛæ¶ÒÉð@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$10543efb-a832-48e9-ae8f-08b589581d71*test2 ¥×æ¶ÃÐð: ýÛ涔Ñð@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$97570e8d-0257-4e25-aa23-e7d6b5372f5a*test2 ¥×æ¶û×ð: ýÛæ¶ËØð@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c4cd6d19-ecb2-42a9-9387-e84bdc236270*test2 ¥×æ¶Çßð: ýÛ涡àð@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4aaad008-2821-470c-93ed-ce26a7d859a1*test2 ¥×涓çð: ýÛæ¶ãçð@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1e4f136f-178e-48a5-a74c-331b82bf4433*test2 ¥×æ¶Ëîð: ýÛ涥ïð@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6cef3406-51cc-453d-99b7-9eea2e92343a*test2 ¥×涡öð: ýÛæ¶ñöð@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$646836ae-436c-45a8-8bd5-84292c6ce649*test2 ¥×涊þð: ýÛæ¶Ûþð@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e36b5391-c660-4c8b-a427-61cdf8cbb8aa*test2 ¥×æ¶Â…ñ: ýÛ涒†ñ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$0925c454-f985-4293-a962-ac63b46501c8*test2 ¥×涬ñ: ýÛæ¶üñ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$06588b02-b5ee-4f1d-beab-12e0b08e8583*test2 ¥×æ¶ø”ñ: ýÛæ¶È•ñ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$513bf431-0e99-43dd-a4fb-2d98c4a4da28*test2 ¥×涰œñ: ýÛ涀ñ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$bf120720-7f8b-4be5-8ea8-38b1c77cd1a5*test2 ¥×æ¶û£ñ: ýÛæ¶̤ñ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b5c286bf-8bbb-45b7-86e1-54327e6ecb44*test2 ¥×æ¶Ç«ñ: ýÛ涗¬ñ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$822a499b-d7fe-4a52-9fce-4529f0328366*test2 ¥×æ¶ÿ²ñ: ýÛæ¶ϳñ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$12337a1e-b962-4417-9d5f-91c361fe8997*test2 ¥×涷ºñ: ýÛ涇»ñ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f948a4ba-959b-4ac2-9048-0a1e8d32113e*test2 ¥×涃Âñ: ýÛæ¶ÓÂñ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$232ff962-65ad-4173-a915-d497bb8d88a7*test2 ¥×涀Îñ: ýÛæ¶ÐÎñ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$dab03081-f37d-4a08-905b-0132d63967f2*test2 ¥×æ¶ËÕñ: ýÛ涛Öñ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d602ec1b-c92a-41ff-ae70-5888eb209384*test2 ¥×æ¶ÉÝñ: ýÛ涣Þñ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3b9f18e1-b656-4a6e-a799-03be38e4ca78*test2 ¥×涋åñ: ýÛæ¶Ûåñ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6486e626-cd83-4a72-94d3-1246876fda3d*test2 ¥×æ¶áìñ: ýÛ涻íñ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7052c4a3-2c3c-423a-ab9d-4c2c109e00a8*test2 ¥×涭ôñ: ýÛæ¶ýôñ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$58c6d98c-5fac-4158-8522-4121387e5524*test2 ¥×æ¶äûñ: ýÛ涿üñ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$efb861c7-8e06-45bd-9ef1-23e602b5c850*test2 ¥×æ¶؃ò: ýÛ涩„ò@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$51c7b6c6-7f61-4528-990d-91ab386483ac*test2 ¥×涚‹ò: ýÛæ¶ê‹ò@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f39e3b76-7fff-4167-86da-edf658771d3b*test2 ¥×æ¶Ò’ò: ýÛ涢“ò@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$dfd6becf-f48d-40f8-8df7-d96ab0f34f5a*test2 ¥×涞šò: ýÛæ¶øšò@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e0e622d7-58ab-4582-b185-9c0745d5450b*test2 ¥×æ¶ô¡ò: ýÛæ¶Ä¢ò@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b269fb22-fa9c-4fc3-8ca3-eb2f28c294a9*test2 ¥×涫©ò: ýÛæ¶ü©ò@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d7462b83-4dbe-4beb-b5dc-9181f70f670b*test2 ¥×æ¶÷°ò: ýÛæ¶DZò@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8b67ac43-f397-4998-acb2-2461d66d7033*test2 ¥×æ¶׸ò: ýÛ涧¹ò@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a00256b7-993f-431e-a56a-aeb2e9ad5af3*test2 ¥×涣Àò: ýÛæ¶óÀò@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$89bdf14e-39ad-42ac-b658-87c0dc01a847*test2 ¥×æ¶åÇò: ýÛ涿Èò@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d6ddbd70-d0ae-4be8-bd21-91354e36d9c3*test2 ¥×涜Ïò: ýÛæ¶÷Ïò@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ec214e58-57bb-483b-b55b-009ed198f034*test2 ¥×æ¶üÖò: ýÛæ¶Ö×ò@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e93e1c78-272a-4b2c-bbe4-c3219c3169af*test2 ¥×涴Þò: ýÛ涄ßò@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a1d6ac0b-1a02-4cf5-ba1e-2a280114628e*test2 ¥×涨æò: ýÛæ¶øæò@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$cb9af70a-265e-4fb3-9c94-abecb3cc35d0*test2 ¥×æ¶óñò: ýÛæ¶Ãòò@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$10d25356-c40f-4c8f-bd5d-04ca13fff54d*test2 ¥×涿ùò: ýÛæ¶úò@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e7bcdc16-43aa-4e67-99f7-82466de74312*test2 ¥×æ¶ì€ó: ýÛæ¶Æó@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2be271be-9d0b-40d0-b830-8193ffb829da*test2 ¥×æ¶̈ó: ýÛ涜‰ó@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$86b925e3-4c0c-4dc0-a875-0ee558a66a5a*test2 ¥×涄ó: ýÛæ¶Ôó@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$80a0d053-4bd2-44f3-9736-89b948d0e945*test2 ¥×æ¶Зó: ýÛ涠˜ó@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3d421e9a-7595-4262-b71a-7ecdd66d8b5e*test2 ¥×消Ÿó: ýÛæ¶ØŸó@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$08592792-b5e3-4a12-949f-d7fe894281dc*test2 ¥×æ¶Ó¦ó: ýÛ涤§ó@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$988ce694-b998-40b8-ba39-368e43cae81f*test2 ¥×涟®ó: ýÛæ¶ï®ó@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$818bdd28-8662-4208-a1f6-714db7293988*test2 ¥×æ¶×µó: ýÛ涧¶ó@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$0d1abf40-447a-4014-9b6b-590a3db00bf4*test2 ¥×涭½ó: ýÛæ¶ý½ó@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$476287cd-2b41-4046-8b7e-35af32de627f*test2 ¥×æ¶ïÄó: ýÛ涿Åó@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2f75c72e-b960-4d62-807b-ae334dff37ec*test2 ¥×涺Ìó: ýÛ涋Íó@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a699e3a4-3f1d-4204-a77b-9f56d0d9f599*test2 ¥×涆Ôó: ýÛæ¶àÔó@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$62e8097b-9aca-4f21-a4bb-657a970362ca*test2 ¥×æ¶ÒÛó: ýÛ涬Üó@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ea627d98-eedf-4e01-a579-683411ec4b8f*test2 ¥×涔ãó: ýÛæ¶äãó@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f3672340-f1db-4468-9dd2-4a1306aed11e*test2 ¥×æ¶àêó: ýÛ涰ëó@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$414e799d-a4c5-4619-9acc-d46e8b02e405*test2 ¥×涗òó: ýÛæ¶èòó@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8f67f06e-62cf-43f8-b175-7691c49ea670*test2 ¥×æ¶Ùùó: ýÛ涩úó@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5734b651-e542-4178-80e6-46f059a60f64*test2 ¥×涛ô: ýÛæ¶ëô@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e1703c3b-31b9-4acc-8e6c-c401fc612712*test2 ¥×æ¶Óˆô: ýÛ涣‰ô@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4bcb71f3-cf69-4200-9212-f3c7b3f8f6ed*test2 ¥×æ¶Óô: ýÛ涞”ô@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4b286a03-e04c-47d2-9105-f37259f412f8*test2 ¥×涅›ô: ýÛæ¶Õ›ô@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$eec75260-38be-482e-a63c-bcfc4607aebf*test2 ¥×æ¶Ñ¢ô: ýÛ涡£ô@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c2d25f3e-d6b7-46ff-8fe9-54852935743f*test2 ¥×涪ô: ýÛæ¶íªô@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$65159c13-70f2-4686-931c-26eb00ae9587*test2 ¥×æ¶é±ô: ýÛæ¶òô@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a1dcb4ed-5ce5-46c9-a5a3-de6c0cd0cc18*test2 ¥×涴¹ô: ýÛ涅ºô@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4b67a9e7-719d-4fca-858d-4d6c3c2be545*test2 ¥×涊Áô: ýÛæ¶äÁô@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$674c4ba4-b8c0-475c-85f6-8d01735d4352*test2 ¥×æ¶àÈô: ýÛ涰Éô@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c535ae7e-6a21-4ca9-943f-79dcabe0abbe*test2 ¥×涘Ðô: ýÛæ¶èÐô@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e9f4e407-7ccb-45fa-9247-2ab5e70b9b38*test2 ¥×æ¶Ð×ô: ýÛ涠Øô@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1b733866-ec47-4105-89d0-faa9b855be15*test2 ¥×涜ßô: ýÛæ¶ìßô@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$00f4f680-34a3-4e77-b375-e0cef8728dc8*test2 ¥×æ¶Éæô: ýÛ涣çô@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$868e6cb0-b4fb-4c0a-9b85-6c391d258bdc*test2 ¥×æ¶åîô: ýÛ涵ïô@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$dfa34225-bbab-4bb9-9ded-ac40f26b7680*test2 ¥×涻öô: ýÛ涋÷ô@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$282c6b85-20d4-4479-a458-d52ba9bc12b8*test2 ¥×涛þô: ýÛæ¶ëþô@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$70a4131a-49d4-446f-8d09-e4ef88656957*test2 ¥×æ¶É…õ: ýÛ涣†õ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$67f060b9-cb35-42ba-b641-db7f17640224*test2 ¥×涟õ: ýÛæ¶ùõ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$344b3218-4e31-42be-a101-98df5e73e12b*test2 ¥×æ¶Ö”õ: ýÛ润•õ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8dafe2ae-3a40-4497-be20-8a3519e80617*test2 ¥×æ¶Àœõ: ýÛæ¶õ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3d95bc21-e165-4d67-9752-69dc054b76eb*test2 ¥×æ¶î£õ: ýÛæ¶Ȥõ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a545416c-9475-4b8c-ae0f-b989806d7202*test2 ¥×æ¶Ä«õ: ýÛ涔¬õ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$cbb74925-2422-4635-b886-e9e4545f35e4*test2 ¥×涚³õ: ýÛæ¶ê³õ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$0773dfca-6b49-42ea-811b-51b07680d0b8*test2 ¥×æ¶Ûºõ: ýÛ涶»õ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$15887271-ce10-42d7-b391-c3e37d966ade*test2 ¥×涓Âõ: ýÛæ¶ãÂõ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1b7c8651-a34c-46c4-b5ae-b8b3fa23425e*test2 ¥×æ¶ËÉõ: ýÛ涛Êõ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c1eab16f-ecde-44ad-9229-da486d36fd1f*test2 ¥×涗Ñõ: ýÛæ¶ñÑõ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d3a351a1-f493-4c9f-8a89-f49b89f12cbd*test2 ¥×æ¶íØõ: ýÛ涽Ùõ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a2776ec2-9fd5-408d-a52d-074ce0c95ebf*test2 ¥×涚àõ: ýÛæ¶õàõ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4a033a4a-d530-46b4-aa78-4a3de5325fcb*test2 ¥×涄èõ: ýÛæ¶Þèõ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$66faa2a1-a1ac-4f0b-a6f7-d317c7007242*test2 ¥×æ¶Æïõ: ýÛ涖ðõ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b564f405-cefa-43b1-bcee-9a7b07b73d55*test2 ¥×消÷õ: ýÛæ¶â÷õ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$549a6f99-e04b-4302-88c1-b6865856f0cb*test2 ¥×æ¶Àþõ: ýÛ涚ÿõ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$029e4dcf-97bd-4f33-99a0-878740258926*test2 ¥×涕†ö: ýÛæ¶æ†ö@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1185540f-5954-47a8-b902-7b2944554a1a*test2 ¥×æ¶áö: ýÛ涱Žö@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c5704c3e-e6b2-4b95-95fa-27505d0af729*test2 ¥×涭•ö: ýÛæ¶ý•ö@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$28950b42-71d6-4848-b102-1439c507184b*test2 ¥×æ¶Рö: ýÛ涠¡ö@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5cc4a310-984c-49c0-9269-784a647fac86*test2 ¥×涒¨ö: ýÛæ¶â¨ö@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$aaecc925-e191-42a8-a07b-c9904d900d23*test2 ¥×æ¶ݯö: ýÛ涮°ö@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$14c75735-74c6-47fd-8f51-5324670e35da*test2 ¥×涩·ö: ýÛæ¶ù·ö@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d5b0f3df-da7a-472b-a8ea-b4d60802f1e7*test2 ¥×æ¶á¾ö: ýÛ涱¿ö@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7dc36491-29ea-4d92-8abe-a0a97a403a86*test2 ¥×涙Æö: ýÛæ¶óÆö@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3f784188-02d3-4eba-adba-a4b48b1126a0*test2 ¥×æ¶ÛÍö: ýÛ涫Îö@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a03fd31f-fdaf-406c-9089-45aa5b713710*test2 ¥×涴äö: ýÛæ¶Þåö@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2798f5c7-a56d-4414-8cf2-8d331da043f9*test2 ¥×涊õö: ýÛ涪öö@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d443d48c-e194-449f-bdd0-87bc78773fe1*test2 ¥×æ¶Þ„÷: ýÛæ¶þ…÷@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b362445f-3e8c-42da-979c-3151e71d4386*test2 ¥×涹“÷: ýÛ涉”÷@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$173c9051-1bd8-4ac7-8517-5be7ad5d97e8*test2 ¥×涅›÷: ýÛæ¶Õ›÷@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$936e5dae-0a5c-46f2-882f-a8eb8536a303*test2 ¥×æ¶Ç¢÷: ýÛ涗£÷@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$37732537-cfa4-4c0c-8bcc-9eff694af9b5*test2 ¥×æ¶õ©÷: ýÛæ¶Ϫ÷@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$06f10235-c1e7-4261-a2f6-bba0c0f854e8*test2 ¥×æ¶ß±÷: ýÛ涯²÷@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ad34cf93-5073-45ba-9e9b-c795b3a72677*test2 ¥×涖¹÷: ýÛæ¶æ¹÷@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1756bc22-bc84-42ae-a591-67cd914a4b35*test2 ¥×æ¶ÎÀ÷: ýÛ涞Á÷@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$03a4f2de-70e0-477c-84fb-afa597dce7a4*test2 ¥×涤È÷: ýÛæ¶ôÈ÷@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e53dbd6f-b3fa-46bc-866e-e454b80e6203*test2 ¥×æ¶ÜÏ÷: ýÛ涬Ð÷@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$980abcdc-e881-4af1-a0ae-e9406268c319*test2 ¥×液×÷: ýÛ涌Ø÷@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9d38618e-66cf-401b-93e6-3b6398cd745a*test2 ¥×æ¶ýÞ÷: ýÛæ¶Íß÷@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3e7d7f26-42df-4c8b-a05f-dcea033114ee*test2 ¥×æ¶Éæ÷: ýÛ涙ç÷@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$90ca6249-052a-433b-84bb-decc11432a62*test2 ¥×æ¶î÷: ýÛæ¶Ñî÷@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7bffb507-1820-46b8-bab5-6e32e9d0b64a*test2 ¥×æ¶Ãõ÷: ýÛ涓ö÷@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8c78b82f-8fbc-4549-a7f3-ca6c951e7afa*test2 ¥×涷ý÷: ýÛ涇þ÷@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$43b91a0b-a1c8-4d19-9b51-eabd5dbc80c2*test2 ¥×涠…ø: ýÛæ¶û…ø@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9c578f8b-3988-443e-83c6-dc6e982d1211*test2 ¥×涊ø: ýÛæ¶Ûø@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$bb4d429f-bd49-41a7-ade2-f9aa436e2a4b*test2 ¥×æ¶Ì”ø: ýÛ润•ø@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b42a686f-3e34-4b78-b0e6-63aa9e2813ff*test2 ¥×涬œø: ýÛæ¶üœø@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1813e52a-222b-40a3-801f-21af94dd9963*test2 ¥×æ¶ä£ø: ýÛ涴¤ø@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c430b057-3780-4613-9f18-6ba93fb9e42f*test2 ¥×æ¶Ϋø: ýÛ涞¬ø@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$22e93144-1730-4c1f-b9a3-2b7dd8982996*test2 ¥×涙³ø: ýÛæ¶ê³ø@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$db807fd3-e703-4e53-bb16-3dfd25934272*test2 ¥×æ¶Ûºø: ýÛ涫»ø@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$de24e2f6-f313-4f64-b455-0415ea52bc61*test2 ¥×涧Âø: ýÛæ¶÷Âø@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d1155f93-5333-4e6d-b86e-f2a8673052b6*test2 ¥×æ¶ßÉø: ýÛ涯Êø@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$efaf24ce-7486-46dc-8036-1813548bb13b*test2 ¥×æ¶ÉÑø: ýÛ涣Òø@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2c5079f4-4dfa-499d-b917-b5f6fa617a8d*test2 ¥×涕Ùø: ýÛæ¶åÙø@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1eab7b0c-e29f-4a2e-b329-3bce2fcaa15d*test2 ¥×æ¶Ìàø: ýÛæ¶áø@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9fea66de-489e-41dd-8bda-ffb6299d6bbb*test2 ¥×æ¶úçø: ýÛæ¶Êèø@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ca1cbeb4-bb1a-4c49-9a44-6eafc60c6f1f*test2 ¥×æ¶Úïø: ýÛ涪ðø@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5c37568f-8019-4d4c-8a8b-a95e1d48a951*test2 ¥×涜÷ø: ýÛæ¶ì÷ø@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$89bccb77-be70-4703-988f-78e85c920a46*test2 ¥×涚ÿø: ýÛæ¶êÿø@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$744cb1f3-0482-4e91-a2a8-98ef3b1f391c*test2 ¥×æ¶Û†ù: ýÛ涬‡ù@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$308d6877-5671-4174-9cb8-6f9c22415af7*test2 ¥×涓Žù: ýÛæ¶íŽù@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5654a9d1-bd12-4df1-8b60-50ef119ed283*test2 ¥×æ¶Ë•ù: ýÛ涛–ù@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3f1d0ac6-94f5-4eb1-9e58-81603c17ee5b*test2 ¥×æ¶ù: ýÛæ¶çù@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$efb4a616-5c6a-4da9-b552-863d1eb4f085*test2 ¥×æ¶Ù¤ù: ýÛ涩¥ù@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5ad635c0-b384-4135-b9f8-d4f8a45a51ab*test2 ¥×涬ù: ýÛæ¶á¬ù@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$68e48c36-8b71-4877-a6bd-9eb0755c9f7e*test2 ¥×涄´ù: ýÛæ¶Ô´ù@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3e2bfc21-7875-4a92-a097-6750d0acc8d6*test2 ¥×æ¶ÿ¾ù: ýÛæ¶Ï¿ù@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$73067cba-85d2-4b41-8de1-e277202c30a6*test2 ¥×涭Æù: ýÛ涇Çù@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$227fe08c-0dc6-492a-b3b5-26f956a123c9*test2 ¥×涃Îù: ýÛæ¶ÓÎù@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$60ba9d23-7824-40c0-9061-ca1532bd45ed*test2 ¥×æ¶ÄÕù: ýÛ涔Öù@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$adc86163-782e-467e-b4e6-568cd67a513c*test2 ¥×æ¶Ýù: ýÛæ¶àÝù@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$32e34cf2-0b64-435b-ab92-cdde39f2da74*test2 ¥×æ¶Òäù: ýÛ涢åù@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$53b73ee4-248a-4dc9-b7f7-e1554dba2da3*test2 ¥×涔ìù: ýÛæ¶äìù@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9141e439-c063-4d41-8525-a2b918fcf60b*test2 ¥×涘÷ù: ýÛæ¶é÷ù@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c1484448-ad83-42b4-9085-5dff92884a2c*test2 ¥×æ¶øþù: ýÛæ¶Èÿù@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e4f6e392-7159-4877-8a5e-633cd518896e*test2 ¥×æ¶Ćú: ýÛ涔‡ú@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2b534ec5-c5e2-4d54-9715-355994b247d5*test2 ¥×涚Žú: ýÛæ¶êŽú@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$dfecbe00-4dc8-4e74-bb10-d8ecd79e91f7*test2 ¥×æ¶Ü•ú: ýÛ涬–ú@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$efb84aa2-9910-4d8b-8032-2806ede9c057*test2 ¥×涓ú: ýÛæ¶äú@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f2c5b7d9-539c-4838-9c6f-ffd261acaaf9*test2 ¥×æ¶Õ¤ú: ýÛ涥¥ú@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$0b2ea347-b3b4-47bc-88a6-3c9f721fca21*test2 ¥×涡¬ú: ýÛæ¶ñ¬ú@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$fb50ce51-7097-4e4e-a7b5-baaf2d754ebb*test2 ¥×æ¶ϳú: ýÛ涟´ú@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1c8c77c6-6121-4aa0-93fa-d980f0eda8b1*test2 ¥×涇»ú: ýÛæ¶×»ú@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$48c6d9c8-004c-4870-bd04-bfb61fe17cb0*test2 ¥×æ¶ÈÂú: ýÛ涙Ãú@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$0f338dfb-c78b-4585-82d7-924e72937253*test2 ¥×涞Êú: ýÛæ¶øÊú@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ed8121eb-5a6f-44a4-b20a-cb45042306a9*test2 ¥×消Òú: ýÛæ¶ØÒú@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$06b4725f-1db4-470c-9109-28fcddc97fb8*test2 ¥×涶Ùú: ýÛæ¶Úú@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$bae33a96-2e1f-42c3-a4d0-94a6950ea165*test2 ¥×涪áú: ýÛæ¶úáú@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3e62e882-aca2-4f36-9a8e-151adea7a41e*test2 ¥×æ¶Øèú: ýÛ涨éú@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$55cd8580-3ef9-49b2-9cb3-25c421ba227d*test2 ¥×涅ðú: ýÛæ¶Õðú@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f309e088-76d8-4fb6-9547-3ccb9ca238ff*test2 ¥×æ¶Ñ÷ú: ýÛ涫øú@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$bddb5590-f589-4158-b653-1a23c4e73400*test2 ¥×涧ÿú: ýÛæ¶÷ÿú@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9c229fc0-af25-4bff-bfcb-b643aa02de5a*test2 ¥×æ¶ý†û: ýÛæ¶͇û@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1caba1ef-74a2-4980-b07c-96fa9a8a97e2*test2 ¥×涫Žû: ýÛæ¶ûŽû@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6d6acc6a-d5fc-458f-8559-c8af861ddfa6*test2 ¥×æ¶ö•û: ýÛæ¶Ç–û@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9fa2dddb-fb69-4d0b-b1ca-b6f546e47e49*test2 ¥×涸û: ýÛ消žû@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f6d5833e-9a5d-4a3f-a64a-4b1e0829cbb3*test2 ¥×æ¶ú¤û: ýÛæ¶Ê¥û@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e5d9d752-fbfd-4b9e-a614-a5f257314e68*test2 ¥×涼¬û: ýÛ涌­û@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b2277c0e-c647-4c83-8141-996284b3a1ac*test2 ¥×æ¶ô³û: ýÛæ¶Ä´û@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$081a1144-de6a-4137-95b5-70b6839ccebf*test2 ¥×涡»û: ýÛæ¶ñ»û@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f9e3133b-9c7b-4afa-89e6-685f90a2d07e*test2 ¥×æ¶Ãû: ýÛæ¶ÛÃû@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ee9f8a38-221b-42e5-bbfb-6e5b2ca094ef*test2 ¥×æ¶ÍÊû: ýÛæ¶Ëû@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$cb446d3a-5c5a-43a6-971b-da82de368a2d*test2 ¥×æ¶ûÑû: ýÛæ¶ËÒû@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d59eb546-894c-4882-ad5b-a9836c6be596*test2 ¥×æ¶ÇÙû: ýÛ涗Úû@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f8ba636e-b5aa-48d3-bb80-c2220f6fff23*test2 ¥×æ¶ôàû: ýÛæ¶Äáû@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ef737bdb-c8f2-47a2-bbb0-5be462c81682*test2 ¥×涢èû: ýÛæ¶üèû@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9b836d1b-865a-4335-b330-faa9527fe950*test2 ¥×æ¶îïû: ýÛ涾ðû@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5b1921f9-ab65-4db6-aad9-aee2f4f47e9f*test2 ¥×涜÷û: ýÛæ¶ö÷û@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$891c7134-5d86-4f8b-9f08-3e056b807763*test2 ¥×涾‚ü: ýÛ涎ƒü@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4b5180e4-4fd7-4cae-995a-3a2d778336b8*test2 ¥×æ¶ö‰ü: ýÛæ¶ÆŠü@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$de24a716-7c1c-49be-83d5-6367fb28348a*test2 ¥×涸‘ü: ýÛ消’ü@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$434e6db1-b105-4fd7-9c33-dd644d21e262*test2 ¥×æ¶æ˜ü: ýÛ涶™ü@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$35ec1a77-104c-40b1-aca9-d4d9bc8722e6*test2 ¥×涧 ü: ýÛæ¶ø ü@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$06b258f0-15d8-443d-82da-416f5696b5a2*test2 ¥×æ¶é§ü: ýÛ涹¨ü@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$db40810a-15f8-465a-91e0-2586dd765b17*test2 ¥×涫¯ü: ýÛæ¶û¯ü@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c4a2c2a0-313d-4987-b8e0-a809fae93090*test2 ¥×涕·ü: ýÛæ¶å·ü@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5c0b27df-8d43-432b-b838-0bccb740cef6*test2 ¥×æ¶×¾ü: ýÛ涧¿ü@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4cef59bd-18dc-47df-ba3a-0f2def1d0328*test2 ¥×涅Æü: ýÛæ¶ÕÆü@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$428c3bd8-93e0-4340-ae07-9a75126abe8e*test2 ¥×液Íü: ýÛ涂Îü@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$efe3bb34-8056-46bf-b5b6-e7110e820aea*test2 ¥×æ¶àÔü: ýÛ涰Õü@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$baea88d1-a1e5-4f37-ba4b-4daef77737c9*test2 ¥×涎Üü: ýÛæ¶èÜü@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$76b766ef-f3a1-40ce-be7a-61fce7b89cf9*test2 ¥×æ¶Ðãü: ýÛ涠äü@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e8b1c113-2d9b-41e5-a95b-9c5f79635536*test2 ¥×涯ëü: ýÛ涀ìü@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e8c489d1-6818-45fa-a0a9-43b8ba85216f*test2 ¥×涠öü: ýÛæ¶ðöü@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d7f87ac7-cb6d-45ab-9762-2d7e3ee7ac4a*test2 ¥×涀þü: ýÛæ¶Ðþü@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1f95f43d-167f-4984-b7ca-ab66addbedbe*test2 ¥×涒†ý: ýÛæ¶â†ý@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$83064daf-fe89-4cad-b4e7-9953d00a1698*test2 ¥×æ¶èý: ýÛ涸Žý@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6de1b91f-9aef-43bd-9cb1-ac63186d6889*test2 ¥×涕•ý: ýÛæ¶æ•ý@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3f73d245-3260-4432-83d9-d958c33b19ad*test2 ¥×æ¶õœý: ýÛæ¶Åý@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8bfcead1-0b5a-4f32-8aa3-37090ca9726c*test2 ¥×涚©ý: ýÛæ¶ê©ý@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4aeb2912-dae2-4527-be70-650c24a5e955*test2 ¥×æ¶æ°ý: ýÛ涶±ý@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d6c80ff1-cb04-45de-a1e4-2816c520a4cf*test2 ¥×涔¸ý: ýÛæ¶ä¸ý@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3847bcf9-ff35-44ee-af94-223806324458*test2 ¥×æ¶ô¿ý: ýÛæ¶ÄÀý@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a032c57c-f452-47b6-985f-166164813917*test2 ¥×æ¶Èý: ýÛæ¶àÈý@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b589dedb-d58a-499f-9cd2-b705741d6e00*test2 ¥×æ¶ÑÏý: ýÛ涢Ðý@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$879995d6-5dca-4bd9-b1e3-a357f5eb813d*test2 ¥×æ¶ÿÖý: ýÛæ¶Ï×ý@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$be2d7983-157b-467e-abe7-5d11b47371a8*test2 ¥×æ¶ëßý: ýÛ涻àý@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f40fb928-91a1-4d24-9475-0e1896cc1fc4*test2 ¥×涭çý: ýÛæ¶ýçý@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3b867776-d0fa-4557-9aa8-beb953702fce*test2 ¥×æ¶åîý: ýÛ涵ïý@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$37084ae1-3e6a-492a-9505-bf20c54f88cf*test2 ¥×涋÷ý: ýÛæ¶å÷ý@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5a86f0a0-c4df-4d97-9a01-72892ae8f9d3*test2 ¥×æ¶Íþý: ýÛæ¶ÿý@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$129b1584-15cf-4eaa-b791-30e39085a18d*test2 ¥×æ¶ú…þ: ýÛ消þ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$eb6e4117-7d1f-4b36-9f94-2fefc7199bc1*test2 ¥×æ¶Æþ: ýÛ涖Žþ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b6a78e2a-b413-4091-8003-137ec230f0e5*test2 ¥×消•þ: ýÛæ¶Ø•þ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$79f9326c-e3e6-4e87-9257-469cda37a178*test2 ¥×æ¶Àœþ: ýÛ涚þ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2d38df86-e2a0-4565-9c51-bec9e29b2756*test2 ¥×涂¤þ: ýÛæ¶ܤþ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9c9567ab-f5e6-418a-aeda-220cce63c8e9*test2 ¥×æ¶Í«þ: ýÛ涞¬þ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ea933aea-fe76-4e13-9bab-9277c69976d4*test2 ¥×涳þ: ýÛæ¶ß³þ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4a83f6db-a558-495f-9d08-989cdb5a3494*test2 ¥×涃»þ: ýÛæ¶Ý»þ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$46a94794-f738-467e-807b-758cf7088d29*test2 ¥×涻Âþ: ýÛ涋Ãþ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f1727c14-05d8-4c73-a3aa-64feebab4e3b*test2 ¥×涤Îþ: ýÛæ¶ôÎþ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3d999429-9153-41c5-b3ee-666ae6db333f*test2 ¥×æ¶ÑÕþ: ýÛ涬Öþ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$0203d985-652e-4685-b125-d2eb5734d166*test2 ¥×æ¶Ýþ: ýÛæ¶íÝþ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$37949954-e15c-4bee-b8a2-b62d32fe91fe*test2 ¥×æ¶Õäþ: ýÛ涥åþ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$046affa3-80df-47a9-8dde-b89eaf86e5fc*test2 ¥×æ¶ìþ: ýÛæ¶Ýìþ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$91ba513d-de84-416a-ab41-4abdf553e2eb*test2 ¥×æ¶ôþ: ýÛæ¶Ñôþ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4a84fdd8-222a-46c2-8b61-f1b34610716f*test2 ¥×æ¶Íûþ: ýÛæ¶üþ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1a3ca638-ff74-43df-8d3e-73bce1b09ba0*test2 ¥×涎ƒÿ: ýÛæ¶߃ÿ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ad9733eb-d9ee-4cfd-8a7b-d9c585caadca*test2 ¥×æ¶ÆŠÿ: ýÛ涖‹ÿ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$37b65fe3-42e2-4252-b10b-9d00900edb0b*test2 ¥×æ¶ô‘ÿ: ýÛæ¶Ä’ÿ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$dddf32df-ad10-4194-881f-71954a9b4a38*test2 ¥×æ¶Ê™ÿ: ýÛ涚šÿ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9f454c2d-70fe-4789-9f63-6a7173c69606*test2 ¥×æ¶ø ÿ: ýÛæ¶Ò¡ÿ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1f2b3657-e79b-42df-80f0-e362770da552*test2 ¥×æ¶èÿ: ýÛ涓©ÿ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b62be380-2815-4853-b482-6381226e46c1*test2 ¥×涅°ÿ: ýÛæ¶Õ°ÿ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b5647692-06dc-497c-85ef-72a1357d0f11*test2 ¥×æ¶Û·ÿ: ýÛ涫¸ÿ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$929213a2-c4cd-4638-b47a-8cb79569bae1*test2 ¥×涉¿ÿ: ýÛæ¶Ù¿ÿ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8562ceca-1716-42bb-9825-9d18102e40a0*test2 ¥×æ¶ÀÆÿ: ýÛ涑Çÿ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$336ef85a-4ec0-47a9-9a0b-f1f29dd3ab8b*test2 ¥×æ¶îÍÿ: ýÛ涾Îÿ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4b9118da-3737-4c9d-abe0-2c83a0906745*test2 ¥×æ¶ÄÕÿ: ýÛ涔Öÿ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f3ee6013-6ac4-49db-9d9d-fee087de74b5*test2 ¥×æ¶èÜÿ: ýÛæ¶ÂÝÿ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c2ad4135-82d6-43a9-b911-799a1d177b45*test2 ¥×æ¶úäÿ: ýÛæ¶Êåÿ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8107330d-fb10-4229-86a2-71fb4bcc8c31*test2 ¥×涖íÿ: ýÛæ¶æíÿ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3b9c2d96-e7ec-4032-b43a-5f246d0f5c95*test2 ¥×液õÿ: ýÛ涂öÿ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$30af276f-a8fb-44fa-a511-619d83a10c06*test2 ¥×æ¶ôüÿ: ýÛæ¶Îýÿ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1fb5de29-c32a-45bc-94ed-61bb89da2cc0*test2 ¥×涵„€: ýÛ涅…€@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7748df4d-afbb-4a61-8edd-a51e476c5452*test2 ¥×æ¶÷‹€: ýÛæ¶ÇŒ€@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3bfa3efe-994d-4243-8330-a55d006aa0f4*test2 ¥×涔€: ýÛæ¶픀@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a7a8d2e4-ead5-46a8-9c7f-a7423cb68045*test2 ¥×æ¶Ë›€: ýÛ涛œ€@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7738ae8a-8c7f-47b4-a5ab-8cceb5a001fc*test2 ¥×æ¶: ýÛ涿£€@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f7921d57-c9d4-4537-8eba-6cf4042f2027*test2 ¥×涺ª€: ýÛ涋«€@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$953c8961-831a-4a4f-9eef-064f5bb44b61*test2 ¥×æ¶ê²€: ýÛ涻³€@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2844f7ad-8f3c-4de9-9501-848af39446b3*test2 ¥×涘º€: ýÛæ¶躀@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b746cd20-49d1-4e28-b15d-8fed5e4c52e7*test2 ¥×æ¶ÚÁ€: ýÛ涪€@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$86a9e847-ea65-4523-a8e7-99b57c3f8634*test2 ¥×消ɀ: ýÛæ¶ØÉ€@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9ac61149-ab8a-4c53-93f0-12c1f7cb6fac*test2 ¥×æ¶ÞЀ: ýÛ涮р@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c987d0bb-2a47-40c2-96ca-2a74ffe5e193*test2 ¥×涀܀: ýÛæ¶ÐÜ€@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$37f57ffb-ccf8-44e0-bf41-4c482fdf20b6*test2 ¥×æ¶Âã€: ýÛ涒ä€@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$84c57768-df28-4332-8094-455e04f8d8dd*test2 ¥×涄ë€: ýÛæ¶Ôë€@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f615744f-1e15-4d89-a6a5-a36eb4e88147*test2 ¥×æ¶Úò€: ýÛ涪ó€@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$cc129644-6f24-4b17-97f0-e89243cb40f1*test2 ¥×涑ú€: ýÛæ¶âú€@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$59349285-8789-42c0-9a9e-13e0a4fcc1fd*test2 ¥×æ¶ñ: ýÛæ¶Á‚@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$38b32934-dab1-407e-901f-6690a5ab755e*test2 ¥×涟‰: ýÛæ¶ï‰@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$03cdd1b1-b51e-4609-8096-b34c7c19557f*test2 ¥×涒•: ýÛæ¶â•@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$28790ddf-491d-4eac-b988-9c23dba32d9f*test2 ¥×æ¶Ôœ: ýÛ涤@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$568fd6d2-2a47-4a2c-99af-0281780326fe*test2 ¥×涖¤: ýÛæ¶æ¤@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$704985b1-a504-4ec9-b23a-aa1beda15281*test2 ¥×æ¶Í«: ýÛ涬@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9e9f48d9-c7d4-439f-ab8d-96637dbba3ce*test2 ¥×涳: ýÛæ¶ß³@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$59952d91-ec37-45f3-add1-4a1e36e89ffd*test2 ¥×æ¶Ѻ: ýÛ涡»@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c0085a0d-f083-4cbe-a97b-1fdf81e91fcb*test2 ¥×æ¶ÿÁ: ýÛæ¶ÏÂ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a57d1d69-3035-417e-b067-1c70eebb84f9*test2 ¥×æ¶ÔÉ: ýÛ涥Ê@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$668fccea-b685-49c8-8332-abbc5ba3e5d7*test2 ¥×涂Ñ: ýÛæ¶ÜÑ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b653ee3a-2021-46b3-83d4-321aefbd9da5*test2 ¥×æ¶ÎØ: ýÛ涞Ù@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a20f3edd-7607-4742-9c75-d74ffdc5c853*test2 ¥×æ¶à: ýÛæ¶àà@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$0270318a-4650-4289-b5cb-cee7d22c9e27*test2 ¥×涾ç: ýÛ涎è@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$90a9440e-4ca5-430d-8839-359814536626*test2 ¥×æ¶ÿî: ýÛæ¶Úï@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b69b200e-7ef9-4026-821d-663a89b80471*test2 ¥×æ¶Ëö: ýÛ涛÷@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6f756181-f485-4689-bdf6-8823b39fa8c2*test2 ¥×涡þ: ýÛæ¶ñþ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$fade2592-3d69-498d-9ae8-11ec047fff68*test2 ¥×æ¶Ï…‚: ýÛ涟†‚@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e99abe32-1683-4ef7-86bf-98583c2af2db*test2 ¥×涇‚: ýÛæ¶ׂ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4ad79914-6268-4952-8b95-42eccb351be5*test2 ¥×涾”‚: ýÛ涕‚@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$837f7741-75fb-4f3a-86aa-a61601feeb3b*test2 ¥×æ¶ö›‚: ýÛæ¶Æœ‚@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e0462448-c962-4344-b0c5-4cab943cc2ee*test2 ¥×æ¶Ö£‚: ýÛ润¤‚@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7d87062a-5e87-4f75-8618-24eead4d8ab8*test2 ¥×涎«‚: ýÛæ¶Þ«‚@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$fba62782-ea0a-45a9-944b-b56a41f646ce*test2 ¥×æ¶в‚: ýÛ涠³‚@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$de623f9d-9983-46f1-8cb3-8edb22516732*test2 ¥×æ¶غ‚: ýÛ涨»‚@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$618cd455-3072-4e26-80a3-2531047e06cc*test2 ¥×æ¶é‚: ýÛ涺Â@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f1a66d5a-0320-4c26-b797-7be48c7e3ba7*test2 ¥×涡ʂ: ýÛæ¶ñÊ‚@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d37d12f3-5678-46be-98d3-b6ca4b80bf48*test2 ¥×æ¶ÙÑ‚: ýÛ涩҂@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6328a538-b43f-45d4-a716-3b944a06003f*test2 ¥×涛ق: ýÛæ¶ëÙ‚@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$98f5a93a-a63b-4583-97fa-a9da131dc554*test2 ¥×æ¶Óà‚: ýÛ涭á‚@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a0b87879-5318-4d26-8d2d-7605ba9be137*test2 ¥×涨è‚: ýÛæ¶ùè‚@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a0311782-721c-4287-a292-023574f2ed81*test2 ¥×æ¶êï‚: ýÛ涺ð‚@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$17e32eed-3239-48a5-a613-368956fea7eb*test2 ¥×涎÷‚: ýÛæ¶Þ÷‚@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$cc3b8312-1c6a-4631-8ac4-2673489d2fb4*test2 ¥×涼þ‚: ýÛ涌ÿ‚@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$93330246-e15c-4092-91dc-67dd515cbf5c*test2 ¥×æ¶þ…ƒ: ýÛæ¶Άƒ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c0273d4b-3dd3-435f-b3b0-fac835771912*test2 ¥×涫ƒ: ýÛæ¶ûƒ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$917724e3-0c56-47b6-b4d5-3b5e4148f400*test2 ¥×æ¶㔃: ýÛ涽•ƒ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ff2e3c9c-86df-4187-8026-2a193ed9f6a9*test2 ¥×涹œƒ: ýÛ涉ƒ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ca34b3b8-4139-4c10-9b07-2592da25b57e*test2 ¥×æ¶û£ƒ: ýÛæ¶ˤƒ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$45c275cc-1800-4636-a92d-773084093042*test2 ¥×涽«ƒ: ýÛ涬ƒ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$fa0b743f-b5f8-4153-9aac-2fa509c1924f*test2 ¥×æ¶ಃ: ýÛ涺³ƒ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$34704eb2-b44b-4371-9d8c-b72a4d055915*test2 ¥×涘ºƒ: ýÛæ¶躃@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$621690b5-c07a-4b90-8309-3063f56cb134*test2 ¥×æ¶ÐÁƒ: ýÛ涠ƒ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7cf8d06f-c6cf-474d-9511-1804ed78e370*test2 ¥×涒Ƀ: ýÛæ¶âɃ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ce27b2df-126f-4c19-9ea2-6ce419b5fce0*test2 ¥×æ¶îÓƒ: ýÛ涾ԃ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3aa02c17-c68e-46b4-a1cb-f7ed9bdb85cf*test2 ¥×润ۃ: ýÛæ¶öÛƒ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6c2c1375-b5e2-4d4b-b253-f32a5c77e4e3*test2 ¥×涮ãƒ: ýÛæ¶þãƒ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d0fff2cc-28e9-47c3-9b2b-2e9f793ba09c*test2 ¥×涢ëƒ: ýÛæ¶üëƒ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$77cda564-c8a9-4257-aa17-f8a0fd5b3113*test2 ¥×æ¶äòƒ: ýÛ涴óƒ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$316c3a02-fc18-4153-a442-f8d8d02acab7*test2 ¥×涛úƒ: ýÛæ¶ìúƒ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4c37215e-960b-46d8-8421-92c4f0f0bd3c*test2 ¥×æ¶Ó„: ýÛ涣‚„@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f4ac69d1-ec71-4e39-a764-a020daffb766*test2 ¥×æ¶쌄: ýÛ涼„@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$502c8775-c060-46e2-a996-090791e21979*test2 ¥×涚”„: ýÛæ¶ꔄ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e884faf3-b702-4f06-bfd0-c09f69a67e07*test2 ¥×æ¶Ç›„: ýÛ涗œ„@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9f290395-e31d-4a61-8d86-351e20db23db*test2 ¥×涧£„: ýÛæ¶÷£„@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b7988299-449c-4047-a493-c913fb3ecf2e*test2 ¥×æ¶ߪ„: ýÛ涯«„@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6965e145-f42b-4dd5-8aad-931d3b98a7fe*test2 ¥×涗²„: ýÛæ¶粄@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$af74a536-2a21-4e09-a180-0135b9a0f000*test2 ¥×æ¶Ù¹„: ýÛ涩º„@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b6a1af1a-f56c-41ea-aaba-0407eaf1e9ff*test2 ¥×涆Á„: ýÛæ¶ÖÁ„@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f0e38978-c892-48d0-b440-fa3b9449619a*test2 ¥×æ¶æÈ„: ýÛ涶Ʉ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$72acc3a4-d35f-4875-8126-5bd070ff5f16*test2 ¥×涔Є: ýÛæ¶îЄ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6be7bbd1-743a-4567-9a81-aecf9e70fe9b*test2 ¥×æ¶àׄ: ýÛ涰؄@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f28f682e-51c7-4367-be11-87e104c30734*test2 ¥×涢߄: ýÛæ¶òß„@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f02304df-2885-4a71-b530-6f7b7b8f0bbe*test2 ¥×æ¶Ùæ„: ýÛ涩ç„@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$bd8aeec1-f95f-40df-b9b3-11431b2f21e1*test2 ¥×æ¶áî„: ýÛ涱ï„@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d503dbf1-8c51-4956-b54a-60b7416239fb*test2 ¥×涷ö„: ýÛ涇÷„@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$0f409770-c12f-49f1-a083-f3fd9138de3e*test2 ¥×æ¶åý„: ýÛ涵þ„@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a0f9954a-3d3e-4ba2-8462-304507fd68a5*test2 ¥×涓……: ýÛæ¶ã……@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$710c999c-478e-43dd-89ef-39f321909b1a*test2 ¥×æ¶茅: ýÛ涹…@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1de18cd5-5ecf-4c8f-bf7d-488605afc6e6*test2 ¥×涪”…: ýÛæ¶ú”…@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$307429f7-c1dc-442b-930d-79006278d7a9*test2 ¥×涀œ…: ýÛæ¶Ðœ…@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ad774e0c-75ac-4427-aa62-20903ecc538b*test2 ¥×涮£…: ýÛæ¶þ£…@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$57e87e2f-5d87-4c4c-a16d-25eafe24fb08*test2 ¥×涎«…: ýÛæ¶Þ«…@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1497643f-9b1f-4e62-b206-3ab4b08a212b*test2 ¥×æ¶ϲ…: ýÛ涪³…@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3ac3d0a7-fff0-4742-8d8f-951dc6ee2b96*test2 ¥×涹º…: ýÛ涊»…@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8385bb93-6a5d-4ab9-9a5b-5d862db8cab7*test2 ¥×涷…: ýÛ涇Å@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3bb431a1-872c-4cf1-a222-6382baa7c894*test2 ¥×æ¶åÉ…: ýÛ涵ʅ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1d3f0f4e-1fe6-4bf6-9809-f25f967ef454*test2 ¥×æ¶ÅÑ…: ýÛ涕҅@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2e7d704a-7df2-4a66-85a3-a19f032753db*test2 ¥×涛م: ýÛæ¶õÙ…@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$02acf654-1aa1-4f4f-9398-308c45dd5fd0*test2 ¥×涣á…: ýÛæ¶ýá…@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$88f4a748-0152-4423-b85a-0fcb7c5f07c4*test2 ¥×æ¶øè…: ýÛæ¶Éé…@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b8a63b9f-204c-4be9-bf33-697e32aca454*test2 ¥×润ð…: ýÛæ¶öð…@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5bf17f7d-5f36-426d-ad3c-08c40d1de037*test2 ¥×æ¶Âø…: ýÛ涜ù…@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8c7256e2-07da-4cce-a083-3b244ffde769*test2 ¥×涘€†: ýÛæ¶耆@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d1e77ded-952e-454c-a7b1-3e4968bad926*test2 ¥×æ¶Ї†: ýÛ涠ˆ†@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f0e318a4-ee32-4a19-8131-2219564fa609*test2 ¥×涺†: ýÛ涊†@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c661c3aa-2b4e-454c-aa23-2af312d7f05d*test2 ¥×æ¶暆: ýÛ涷›†@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a2f48428-85e6-4923-92cb-739b738f4490*test2 ¥×æ¶Ú¢†: ýÛ涪£†@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$95fc9a90-fed6-4133-80e7-b98a32e09e6a*test2 ¥×涒ª†: ýÛæ¶⪆@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$59965f7d-1539-4d69-8b50-e73b8417223b*test2 ¥×涆²†: ýÛæ¶Ö²†@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4be09630-6be7-4d48-ab9f-e1b8d77dfc90*test2 ¥×æ¶Ò¹†: ýÛ涢º†@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$deb3abbb-a1d5-4204-974c-103ef076fb6f*test2 ¥×æ¶ÆÁ†: ýÛ涖†@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d78313ad-4465-4f41-9165-6f455ad0bbdc*test2 ¥×æ¶óȆ: ýÛæ¶ÄɆ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5ff13621-2a6d-462b-906e-a5c6719acb9c*test2 ¥×涫І: ýÛæ¶ûІ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b1fe8e6c-dd66-4bfb-9601-7860032ab7eb*test2 ¥×æ¶í׆: ýÛ涽؆@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$72214cc9-d00b-45b1-8c55-bb7975266776*test2 ¥×æ¶Ã߆: ýÛ涓à†@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8af5fc00-15ea-41ed-8380-44dafc87cc7a*test2 ¥×涙ç†: ýÛæ¶óç†@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9138e5cf-8107-4a9d-8319-b4d05c034142*test2 ¥×æ¶Ðî†: ýÛ涡ï†@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e258c0ed-e49a-4e06-a2f7-62687775acbf*test2 ¥×æ¶þõ†: ýÛæ¶Îö†@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f1263a4d-2d02-4dce-9f43-c31eec29a1e4*test2 ¥×æ¶Àý†: ýÛ涚þ†@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$227f258c-0723-4598-9758-f2fac4fcdbf4*test2 ¥×æ¶ø„‡: ýÛæ¶È…‡@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$efd99a62-1045-4d39-96d7-27159b3d76b6*test2 ¥×æ¶ÄŒ‡: ýÛ涔‡@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$07e1a612-d9f5-41c9-a9bb-b4a55439f41e*test2 ¥×涅”‡: ýÛæ¶Ö”‡@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f43d77b9-8643-431c-ab2a-b2a42673e18d*test2 ¥×涳›‡: ýÛ涃œ‡@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$aa63080e-1195-4c21-926d-120b5f29bcd8*test2 ¥×涉£‡: ýÛæ¶㣇@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$02053305-ec28-47fc-8783-f9a109b2a673*test2 ¥×æ¶Áª‡: ýÛ涑«‡@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$0e95d039-9563-4916-8339-81dc828b8bad*test2 ¥×æ¶Ó²‡: ýÛ涣³‡@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3f878ddb-5166-453b-bc19-826a30ce34c8*test2 ¥×æ¶ͽ‡: ýÛ涞¾‡@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$69ab04f0-0c79-415a-a84d-abe67d06ad75*test2 ¥×æ¶Ň: ýÛæ¶ßŇ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ed110a34-ed93-47b7-ac7c-cb1df2011b21*test2 ¥×涡͇: ýÛæ¶ñ͇@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7d9cedb2-f365-4445-99ff-f89118fc1c81*test2 ¥×æ¶÷Ô‡: ýÛæ¶ÑÕ‡@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5c5e435b-0c4e-43d2-8307-f176f194d6eb*test2 ¥×涯܇: ýÛæ¶ÿ܇@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f71703a6-8d63-40fb-b859-f658e73ea660*test2 ¥×æ¶ûã‡: ýÛæ¶Ëä‡@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5bbc972e-0bbd-40d5-abb1-0ab7f18fd5a4*test2 ¥×涗ì‡: ýÛæ¶ñì‡@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8dc00be9-d824-4477-98a3-ffb46a737d38*test2 ¥×涞ô‡: ýÛæ¶ïô‡@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$21a9f630-738f-4db1-97c7-1263fbcd38a1*test2 ¥×æ¶àû‡: ýÛ涰ü‡@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9409c905-d0ec-40b8-a192-f35579cc41db*test2 ¥×涢ƒˆ: ýÛæ¶òƒˆ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7717392a-be36-4f9e-a616-7f16b1d2f6b2*test2 ¥×æ¶ð‹ˆ: ýÛæ¶ÀŒˆ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$924e543a-54d3-4648-b30c-9a12a17b166b*test2 ¥×æ¶Гˆ: ýÛ涪”ˆ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$613cff84-f98e-48af-84d7-ba3d1014840a*test2 ¥×æ¶þšˆ: ýÛæ¶Ø›ˆ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e48c277c-20e0-4397-b1a2-80df29d165af*test2 ¥×æ¶Ê¢ˆ: ýÛ涚£ˆ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f373db10-e8dc-4b2a-928f-e4adb1d9c7ce*test2 ¥×æ¶Ûªˆ: ýÛ涬«ˆ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2e047b15-0330-4c1e-ad1b-7c0209b3ad0b*test2 ¥×涉²ˆ: ýÛæ¶Ù²ˆ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8b227997-b1c4-401e-85fd-70c0267e66d2*test2 ¥×涥ºˆ: ýÛæ¶õºˆ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a49eddf6-4a74-4e19-973b-371eb3a7b947*test2 ¥×æ¶ÓÁˆ: ýÛ涣ˆ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5c39f40e-162c-4800-a5cb-931f6270018b*test2 ¥×æ¶ïɈ: ýÛ涿ʈ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b4c26853-2cda-4dd8-89a8-cf5665cdd8fb*test2 ¥×æ¶Ùш: ýÛ涩҈@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$79bb586e-8b36-4cf2-a9dc-ef125ec80ead*test2 ¥×涑و: ýÛæ¶áÙˆ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e15d462e-9498-43a8-8e53-bd7cfdd8ecfd*test2 ¥×涟äˆ: ýÛæ¶ïäˆ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f86c6285-aaea-4484-8feb-8343250cda05*test2 ¥×æ¶×ëˆ: ýÛ涧ìˆ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b05d4612-ad55-4500-bb18-b6c46ac8c65c*test2 ¥×æ¶ýóˆ: ýÛæ¶Íôˆ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2aa7bfec-0b63-4a57-81a7-21d5e3f8a77c*test2 ¥×涿ûˆ: ýÛæ¶üˆ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9587116b-9263-4042-a8fd-126316d1c4e5*test2 ¥×æ¶킉: ýÛ涽ƒ‰@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f8bd14ec-0be7-499c-9afa-d34d3411f990*test2 ¥×涉‹‰: ýÛæ¶Ù‹‰@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$71853749-6d5d-4b7d-b7d5-a59b3e9b3187*test2 ¥×æ¶Ô’‰: ýÛ涤“‰@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7b3e7d0c-f147-4883-9bee-a1bba3c43add*test2 ¥×涖š‰: ýÛæ¶暉@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$97b31d27-b568-43ff-9b65-51d65885b814*test2 ¥×æ¶Ρ‰: ýÛ涞¢‰@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$efb554ae-a399-4d72-a849-6e7dec556634*test2 ¥×æ¶ü¨‰: ýÛæ¶Ì©‰@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ce74c472-0ea6-42a4-8519-aa2d533cf40e*test2 ¥×涽°‰: ýÛ涎±‰@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6a7a1adb-1b2c-4ef7-8707-7fcf235b125d*test2 ¥×æ¶õ·‰: ýÛ涟‰@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d1071307-33db-4537-ab4c-55bdd96fe89c*test2 ¥×涷¿‰: ýÛ涇À‰@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8308cd22-187b-463d-a928-fb44c2ef37b3*test2 ¥×æ¶ùƉ: ýÛæ¶Élj@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$0012845e-67ae-42d4-92fe-8b81fb56c271*test2 ¥×æ¶ÏΉ: ýÛ涟ω@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c656f32c-6826-4b6a-b199-7eb1d776da25*test2 ¥×æ¶òÕ‰: ýÛæ¶ÍÖ‰@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2b312fbf-9600-4407-9afb-8d3c62eb5b31*test2 ¥×涪݉: ýÛæ¶ú݉@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$784a8476-7f08-4a7d-a19b-0dd68a21a353*test2 ¥×涼å‰: ýÛ涌æ‰@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$58274b7d-f738-497c-8abb-ecc52ce39e10*test2 ¥×涰í‰: ýÛ涀î‰@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3b2e37e2-93f6-4232-8e3b-0c4dc15e6fcc*test2 ¥×涆õ‰: ýÛæ¶Öõ‰@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7ab5bb95-54d5-40a8-acbd-81266c5a7a85*test2 ¥×æ¶Èü‰: ýÛ涘ý‰@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b3581d6c-c3a7-4c4f-a8c3-fad6783a88f8*test2 ¥×æ¶ä„Š: ýÛ涴…Š@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6b46d405-6b6e-4fad-a26c-52ffd1d5580f*test2 ¥×æ¶öŒŠ: ýÛæ¶Њ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f0135c58-ed3a-48ec-899c-815765047abe*test2 ¥×涭”Š: ýÛæ¶þ”Š@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$919ea080-db2d-473f-aa60-d92521224f2b*test2 ¥×æ¶Û›Š: ýÛ涫œŠ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$0ce1d97c-2d7f-40c5-95b1-53ff8375f1e8*test2 ¥×涣Š: ýÛæ¶í£Š@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4b08759c-474a-4050-b473-63620fc6ef3d*test2 ¥×æ¶ëŠ: ýÛ涓¬Š@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a32705dc-d40f-4d47-b343-c9ac8ac0a577*test2 ¥×æ¶ñ²Š: ýÛæ¶Á³Š@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7000326a-e501-4951-bcf2-8887034be7e6*test2 ¥×æ¶ѺŠ: ýÛ涡»Š@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f1d1fd38-b65e-45b7-b451-0ab4aa0f3c2e*test2 ¥×涒Š: ýÛæ¶âŠ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f0899139-8a77-48e9-bb06-63f934e3f3be*test2 ¥×æ¶ÊÉŠ: ýÛ涚ʊ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f2ed75d2-d599-4938-bc46-de9585e7f941*test2 ¥×涖ъ: ýÛæ¶æÑŠ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$fd8dabbf-aa9d-4e77-8d9c-c1c7bef5afd1*test2 ¥×æ¶âØŠ: ýÛ液ي@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$161aff99-e25c-45b8-ab11-194b519942e6*test2 ¥×æ¶àŠ: ýÛæ¶ààŠ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5c15ce41-6241-4100-87bd-647fd7b59495*test2 ¥×涫èŠ: ýÛæ¶üèŠ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$0869a6e6-eb71-42a1-ba72-b0dcdf9d4aa6*test2 ¥×æ¶þòŠ: ýÛæ¶ÎóŠ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$180e1248-40f0-48fb-8a18-91ff3e279c6b*test2 ¥×涶úŠ: ýÛ涆ûŠ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a8c2fb49-d95b-4f33-9418-a4e9f1954800*test2 ¥×æ¶Ü‚‹: ýÛ涬ƒ‹@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$caacd532-9155-451e-80e8-f3973ced0146*test2 ¥×涨Š‹: ýÛæ¶øŠ‹@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f0a9b19a-2870-4bb1-9d3d-2317935dac87*test2 ¥×æ¶ß‘‹: ýÛ涰’‹@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$43ae6811-71f0-45f6-9084-4d8468b8830d*test2 ¥×æ¶Ó™‹: ýÛ涣š‹@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2036b715-35c3-45d8-983f-16a830750c63*test2 ¥×涡‹: ýÛæ¶Ñ¡‹@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$95bf3b18-955b-4078-ba7a-8fdd5bdde14d*test2 ¥×æ¶媋: ýÛ涶«‹@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f9d637cb-a4ff-4a98-8ad2-16118b4639f0*test2 ¥×æ¶Ų‹: ýÛ涕³‹@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6337b9e6-6e20-48b7-a438-eea1e91e6381*test2 ¥×æ¶õº‹: ýÛæ¶Å»‹@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$798db95b-2437-4c4b-ab30-7a2c1527f82d*test2 ¥×æ¶Õ‹: ýÛ涥Ë@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b0c2350c-0013-4c11-b8dc-3a6339de8bbc*test2 ¥×æ¶ÉÊ‹: ýÛ涣ˋ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$13af0c32-5089-43a8-910c-f58007c297a9*test2 ¥×涋ҋ: ýÛæ¶ÛÒ‹@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1c2b9631-44cc-4ff7-acc5-e23ce70586d2*test2 ¥×涓ڋ: ýÛæ¶íÚ‹@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f8ba8fa6-b8ae-4125-b12e-a5e0ea164edc*test2 ¥×æ¶ãã‹: ýÛ涳ä‹@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$67f8fe2f-236e-4bb7-8978-311754adda84*test2 ¥×涛ë‹: ýÛæ¶ëë‹@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5509ae81-90dd-4a11-b962-bc62925e8c11*test2 ¥×æ¶Óò‹: ýÛ涣ó‹@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b0e05651-aecf-4b76-96a3-0bb62d24f0b7*test2 ¥×液ú‹: ýÛ涃û‹@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b6b04508-7fa6-40de-997e-486b2d864db2*test2 ¥×æ¶àŒ: ýÛ涰‚Œ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f3775015-c265-4eae-8378-843f3a35dd21*test2 ¥×涘‰Œ: ýÛæ¶艌@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$0f9164ac-1a2a-42cf-ae7f-48cac54d501e*test2 ¥×æ¶ÐŒ: ýÛ涠‘Œ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c2cbe093-306b-481c-b2c9-e504e60bac21*test2 ¥×涒˜Œ: ýÛæ¶☌@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4329eddb-3708-43ee-bde7-2cd8e1545680*test2 ¥×涵ŸŒ: ýÛ涠Œ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$bb6f48c5-14f7-4c4d-beba-0e8af543eea1*test2 ¥×æ¶÷¦Œ: ýÛæ¶ǧŒ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$daaf83c8-5b61-454c-8bcf-fa5e1cb76817*test2 ¥×æ¶×®Œ: ýÛ涱¯Œ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$bcf3d90c-fb15-4af6-8d0d-cecb002cb133*test2 ¥×涣¶Œ: ýÛæ¶ó¶Œ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1237ba2d-eabb-4a0f-a3d3-87531a147173*test2 ¥×æ¶ѽŒ: ýÛ涡¾Œ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8f124a11-73c7-41fa-a2fb-573d5c3753f4*test2 ¥×涒Ō: ýÛæ¶âÅŒ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4f887b42-6389-403b-9a83-a0265cc4b4ad*test2 ¥×æ¶ÞÌŒ: ýÛ涮͌@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$80b03a97-8f9d-48bc-8584-ad5124806d06*test2 ¥×涂Ԍ: ýÛæ¶ÒÔŒ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c1ac4233-4b69-4aad-8d8b-99cb3df12615*test2 ¥×涰ی: ýÛ涀܌@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$fef8acb1-5364-4405-be05-50e85d2990e6*test2 ¥×æ¶ÝâŒ: ýÛ涮ãŒ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$76adf38c-6ed1-4ef8-8121-b32da45904c1*test2 ¥×涋êŒ: ýÛæ¶åêŒ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3f766c14-1ad0-4902-94fb-b3dbb97b47ee*test2 ¥×æ¶õñŒ: ýÛæ¶ÏòŒ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b8d83cef-f56a-4bcd-8598-d8c2ad85c431*test2 ¥×涭ùŒ: ýÛæ¶ýùŒ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c93cd754-3e97-42a5-8a16-bb8049e80dae*test2 ¥×涃: ýÛæ¶Ó@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$25173e04-eb1b-4f7e-9fd4-f178cef35658*test2 ¥×æ¶؈: ýÛ涳‰@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a8ebe0e9-8efa-4e8a-b876-ea6a86935db9*test2 ¥×涆: ýÛæ¶Ö@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e27460b0-b2ea-4a74-8fd7-322e6c95f70a*test2 ¥×涴—: ýÛ涄˜@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$df372c40-14e6-46db-9d49-5d01f6d9092f*test2 ¥×涀Ÿ: ýÛæ¶П@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ac82147f-6b39-4c94-8518-0635a1439d54*test2 ¥×润: ýÛ涒§@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ea083218-7fbe-4acd-bab3-5fd5d8eaad9f*test2 ¥×涃®: ýÛæ¶Ô®@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6a8a8903-e1a6-4453-8323-23300dca3e56*test2 ¥×æ¶ϵ: ýÛ涟¶@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1e51f09e-e874-48a6-94c1-b0afd9cf5451*test2 ¥×涑½: ýÛæ¶á½@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$bfe64ed2-62a7-45c8-bb04-f5f8524e8b92*test2 ¥×æ¶çÄ: ýÛ涷Å@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3e08a95e-f6a8-462b-ad88-8aff7a23f2be*test2 ¥×涕Ì: ýÛæ¶åÌ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$769b4f46-bbdd-42b1-8cbf-db861f9d49de*test2 ¥×æ¶àÓ: ýÛ涱Ô@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$14249ab6-4cd9-44e5-b509-bcda8d9f16e6*test2 ¥×涘Û: ýÛæ¶èÛ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7f97d19e-6ac6-491c-833d-01da03f4a22a*test2 ¥×æ¶Úâ: ýÛ涴ã@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9c560e24-13cb-4f21-a3d6-c46e45c19db6*test2 ¥×涥î: ýÛæ¶ÿî@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$09d40013-fbe2-45e2-aa31-bf6d7b558fdd*test2 ¥×æ¶Ýõ: ýÛ涭ö@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$34d517b4-d0bd-4d2e-9076-319b763f8718*test2 ¥×液ý: ýÛ涃þ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$56d170ea-869b-443b-ae98-e4d48bcb545b*test2 ¥×æ¶ê„Ž: ýÛ涺…Ž@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$95332e12-d7cf-459a-b61f-82677e6e4ffd*test2 ¥×涬ŒŽ: ýÛæ¶üŒŽ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7e8fe826-c1e2-4400-be6b-f7f7c78fa922*test2 ¥×æ¶ä“Ž: ýÛ涾”Ž@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9d4d505c-cfa1-442e-ab1f-2db1786853a6*test2 ¥×涒›Ž: ýÛæ¶⛎@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$466a31fc-aa87-4f95-84b4-f408b9e74338*test2 ¥×涊¥Ž: ýÛæ¶䥎@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4f0c6d36-7244-4dbc-8f0d-5085374fb6ab*test2 ¥×涬Ž: ýÛ涒­Ž@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b20389e7-6203-4f11-bc5b-15bf274e7cb8*test2 ¥×涴Ž: ýÛæ¶Þ´Ž@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7b3fa211-783d-40d7-bfbf-508dd8b5dc4d*test2 ¥×æ¶í»Ž: ýÛæ¶ȼŽ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$cf1f8c2d-9089-4aea-811f-0919113ddd2d*test2 ¥×涥Î: ýÛæ¶õÃŽ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7be8448b-a3bd-421f-86c8-51f82ec27bdb*test2 ¥×æ¶çÊŽ: ýÛ涷ˎ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$52397220-5a67-42d7-befb-3d9a69578997*test2 ¥×涩Ҏ: ýÛæ¶ùÒŽ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8c52f717-f038-4294-b81d-eebe3df52d69*test2 ¥×涉ڎ: ýÛæ¶ÙÚŽ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$82b73130-271e-48ea-9fed-dcd53a45109f*test2 ¥×æ¶ÊáŽ: ýÛ涛âŽ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f1761015-b890-4e7c-bdae-0e99c54c7e42*test2 ¥×涌éŽ: ýÛæ¶ÜéŽ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c77d8f22-e06f-4639-b232-06a8b8408a92*test2 ¥×æ¶âðŽ: ýÛ液ñŽ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$31cc9482-7cca-4b85-91d9-35455ed011b4*test2 ¥×æ¶ôøŽ: ýÛæ¶ÄùŽ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e7a327ff-98bf-442b-84a8-c9f28fdf621d*test2 ¥×涶€: ýÛ涆@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d7ed031b-5c9e-4519-8935-94179c7d0ada*test2 ¥×æ¶î‡: ýÛ涾ˆ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$41c76959-3487-488a-9d8a-5c9cdd1ddaaf*test2 ¥×æ¶Ã: ýÛ涔@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$fa9cc705-2e70-4ff7-a77e-422244b23b19*test2 ¥×æ¶ñ–: ýÛæ¶Á—@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b34d505c-71ee-4734-bcd2-b01a09ec7306*test2 ¥×æ¶åž: ýÛ涿Ÿ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9f0ad413-e7e1-4da6-b716-815200f0c832*test2 ¥×润: ýÛæ¶í¦@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ab3b4e5f-662a-4ef6-a7b7-5761a5696242*test2 ¥×æ¶ß­: ýÛ涯®@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b53e5c2e-7b91-4e67-84a0-8fe90ef7deb4*test2 ¥×涴µ: ýÛ涅¶@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$348634c3-f7b1-46f4-80b7-391403b3d0d5*test2 ¥×涔½: ýÛæ¶ä½@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2b4e4be6-00b7-40df-9658-b03cf3d04197*test2 ¥×æ¶ÖÄ: ýÛ润Å@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d438bf2d-b094-492e-a143-6b261388fb75*test2 ¥×涄Ì: ýÛæ¶ÞÌ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1d0882a8-ecf7-4b88-8ea7-f78237f43e1a*test2 ¥×涼Ó: ýÛ涌Ô@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d6a5e28f-ddb5-41f8-8882-1b1f241569b2*test2 ¥×æ¶éÚ: ýÛ涺Û@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$93ce9dc6-fa7b-46e1-b82a-2d58d07a62ac*test2 ¥×涡â: ýÛæ¶ûâ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1e4ea86d-48fa-4682-b3d3-6acaa406b090*test2 ¥×æ¶Ùé: ýÛ涩ê@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$60b7cc71-aa20-4d3e-b61c-485b64bd9a4d*test2 ¥×涹ñ: ýÛ涉ò@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a40518e7-bb01-401d-b858-df633fee489f*test2 ¥×æ¶ûø: ýÛæ¶Õù@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8e64998f-9509-409c-96ca-d9ace4ce9a0b*test2 ¥×液€: ýÛ涃@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f7091bf4-dafe-4dac-8e9e-7bd06fce3735*test2 ¥×æ¶ô‡: ýÛæ¶Ĉ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$747cb444-41a2-4525-981d-af11f173d782*test2 ¥×涶: ýÛæ¶@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d33c9120-6470-441d-9224-5757cc1102a4*test2 ¥×涂—: ýÛæ¶Ò—@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7ee69898-8596-4e9c-b26d-7d83a6999681*test2 ¥×涰ž: ýÛ涀Ÿ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e8f1f8d7-3870-4ca2-95b9-f0f2f832c806*test2 ¥×æ¶Ý¥: ýÛ涭¦@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3f3ec68f-a7eb-4332-a492-a8d5aee41178*test2 ¥×涞±: ýÛæ¶î±@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$bd2ce203-9cb4-400d-a8d4-5191c9a867c9*test2 ¥×æ¶Ö¸: ýÛ润¹@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c24b66ab-92bf-457f-bbc4-7685931d1d3a*test2 ¥×涢À: ýÛæ¶òÀ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d2292292-9cf7-461b-bc80-6b33cb6b5a8a*test2 ¥×æ¶ÏÇ: ýÛ涠È@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$40210699-7bee-4d25-89f1-e1ea4a8ec269*test2 ¥×涛Ï: ýÛæ¶ëÏ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ae093f85-f208-45b8-a9fc-2547e8f74f00*test2 ¥×æ¶ûÖ: ýÛæ¶Ë×@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4a96c26c-7d2e-43b8-b46b-d739620b3352*test2 ¥×涩Þ: ýÛæ¶ùÞ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d6358903-907e-4ac7-b867-0bcf4b841a2d*test2 ¥×æ¶ëå: ýÛ涻æ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7b4996a7-8043-4598-be96-cb7c2966e048*test2 ¥×涢í: ýÛæ¶óí@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$fb18f958-694b-4689-8247-58112aa08e3c*test2 ¥×æ¶îô: ýÛ涾õ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5b6fb387-e394-4ba0-bd78-104f07f22aa8*test2 ¥×涜ü: ýÛæ¶ìü@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$bec794de-e1c6-4028-bf8b-dca922dec00c*test2 ¥×æ¶Ôƒ‘: ýÛ涤„‘@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e781f327-00c1-48f8-8ec1-5bb20d5418ac*test2 ¥×涂‹‘: ýÛæ¶Ò‹‘@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1144938d-1101-45d0-a213-5ba382f48663*test2 ¥×æ¶Ã’‘: ýÛ涓‘@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$270f0fe1-3246-4440-8849-a2bce2c9e34f*test2 ¥×æ¶û™‘: ýÛæ¶Ëš‘@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1d4cabd3-2276-4e75-a9e3-da96630fc1f5*test2 ¥×涩¡‘: ýÛæ¶ù¡‘@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$73202ecf-9653-458a-86ff-14fa2091f349*test2 ¥×æ¶ᨑ: ýÛ涱©‘@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$fe86c3ee-b4f7-4b3b-8d31-e95937798366*test2 ¥×涎°‘: ýÛæ¶é°‘@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2c3cb4d4-6f54-4cd9-88a5-471658037e6f*test2 ¥×æ¶ä·‘: ýÛ涾¸‘@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$29c4e679-a958-4234-9955-16205c90434c*test2 ¥×涒¿‘: ýÛæ¶ì¿‘@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b1a8faca-5421-4fbc-8966-0a834ef20b87*test2 ¥×æ¶ÀÆ‘: ýÛ涚Ǒ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d4681be9-75e8-4612-aba7-0ab8862ce470*test2 ¥×æ¶Ò‘: ýÛæ¶ÑÒ‘@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d9d21df5-351a-4645-bd88-786c72cc5c4f*test2 ¥×涮ّ: ýÛæ¶þÙ‘@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4eb6a700-4552-4f8d-bbcf-d8850afd0d18*test2 ¥×æ¶æà‘: ýÛ涶á‘@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$da8f1db8-4702-4533-b116-535f00f8a6a7*test2 ¥×液è‘: ýÛ涂é‘@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f0855333-ecf3-4377-b0bc-a5ebb3796e27*test2 ¥×æ¶àï‘: ýÛ涺ð‘@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a55c2c63-8db8-438d-b43d-3b4b7abb435e*test2 ¥×涗÷‘: ýÛæ¶è÷‘@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e1fb1b3a-100f-4a04-a4b5-7155bae125bf*test2 ¥×æ¶÷þ‘: ýÛæ¶Çÿ‘@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$619847e4-b329-4831-8cf9-68a10a02acc0*test2 ¥×æ¶Æ’: ýÛ涓‡’@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c41699a7-efda-44e9-9600-0191d22104d7*test2 ¥×涎’: ýÛæ¶ߎ’@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b6701edc-b2d1-457a-8ce0-1d677e091ad5*test2 ¥×æ¶Ç•’: ýÛ涗–’@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$227cba49-c0ee-4deb-bf50-28c7fc865fb4*test2 ¥×涒’: ýÛæ¶ã’@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$33f3869d-e019-4be2-a677-14fb037e1063*test2 ¥×æ¶Ô¤’: ýÛ涤¥’@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5b6ac3df-1506-4f87-884c-a70c05a2355b*test2 ¥×涠¬’: ýÛæ¶ð¬’@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2b36a8f9-c9ed-402d-8791-574b32c85489*test2 ¥×æ¶â³’: ýÛ液´’@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$52db4dbb-0162-4785-a867-6448b26e0e7b*test2 ¥×涮»’: ýÛæ¶þ»’@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ee99f358-fe89-431d-9b0b-9ac918795d85*test2 ¥×æ¶ÛÂ’: ýÛ涬Ò@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$0784e089-0c94-45f4-92ff-ab079a0dd213*test2 ¥×涧ʒ: ýÛæ¶÷Ê’@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$399bb283-e525-405c-a900-64b78398de57*test2 ¥×æ¶éÑ’: ýÛ涹Ғ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6e575806-fda0-4afb-90fc-dbcc7e65a23f*test2 ¥×涡ْ: ýÛæ¶ñÙ’@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f0d7707a-1acf-482c-830e-b230b693578d*test2 ¥×æ¶Ùà’: ýÛ涩á’@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b9cd0a38-1a99-4a0e-8a95-6c898955de1d*test2 ¥×涤è’: ýÛæ¶õè’@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$312cf84c-e469-44fe-af53-deeb34bf6a89*test2 ¥×æ¶ô’: ýÛæ¶Ýô’@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d6dc3c9b-41d1-4a06-a700-e170321791fe*test2 ¥×æ¶Ïû’: ýÛ涟ü’@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$efde7125-987a-4175-8f9f-e8f29f0852ff*test2 ¥×涑ƒ“: ýÛæ¶დ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e79ed41e-69c3-4aa5-976c-82e1160111d3*test2 ¥×æ¶ÝŠ“: ýÛ涭‹“@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$29a56b78-a3ca-4dc8-ac46-2b0789747246*test2 ¥×涔’“: ýÛæ¶å’“@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ab4b84dc-72c9-48ed-9d9e-8a13f92caf58*test2 ¥×æ¶Ö™“: ýÛ润š“@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$68253964-7419-494e-9631-c9e9f652e8ee*test2 ¥×涬¡“: ýÛæ¶ü¡“@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$eeebc724-20b2-4103-aa29-fe7b37d34408*test2 ¥×涖©“: ýÛæ¶æ©“@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$911194af-e106-4beb-8623-4f45e8eb1fed*test2 ¥×æ¶ΰ“: ýÛ涞±“@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e8211902-ba46-466e-9808-4ab48d8dda5c*test2 ¥×æ¶ü·“: ýÛæ¶̸“@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$dde09b86-9cef-474d-a443-ba2a15ce61ae*test2 ¥×涽¿“: ýÛæ¶À“@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c0c7c745-cea4-4a18-992a-b307b133ca39*test2 ¥×æ¶ëÆ“: ýÛæ¶ÅÇ“@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$04ffbebd-6907-4441-b21c-1260818f50c5*test2 ¥×涷Γ: ýÛ涇ϓ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$eaa450d6-e2f5-4c15-bc34-e93d50838b6a*test2 ¥×æ¶Ö“: ýÛæ¶ÝÖ“@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6f8ab06f-d0f4-4c6c-9f0c-4f4dfd5e19a3*test2 ¥×æ¶ÏÝ“: ýÛ涩ޓ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$20c71a6a-ae26-40a9-8da8-06e6016c2611*test2 ¥×涆å“: ýÛæ¶Öå“@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b87cdc9a-6755-4bd4-aed0-cee0f310820a*test2 ¥×涾ì“: ýÛ涘í“@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$96a478c0-45b0-4546-a198-2c7866faff86*test2 ¥×æ¶ìó“: ýÛ涼ô“@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$68adc210-6e0e-4118-b4a6-52395728f986*test2 ¥×æ¶Öû“: ýÛ润ü“@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8bbfcb43-144b-4119-a8f0-81e39b6e0974*test2 ¥×涎ƒ”: ýÛæ¶Þƒ”@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$09868a14-809f-47bf-b4a8-d2ad88201f7e*test2 ¥×涻Š”: ýÛ涋‹”@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$23f1a818-2329-4d21-8e22-b39dc6106459*test2 ¥×涑’”: ýÛæ¶á’”@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2031750e-6036-47a4-897b-eab076a5f32d*test2 ¥×æ¶É™”: ýÛ涙š”@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$943bfd94-90e8-4a93-bd55-ca7073ef0d74*test2 ¥×æ¶÷ ”: ýÛæ¶Ç¡”@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4db7901c-1992-4741-9ea4-d1f8cb63b4a4*test2 ¥×涤¨”: ýÛæ¶õ¨”@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4d2d3db2-ee98-47c5-8e28-235f791f1391*test2 ¥×æ¶ð¯”: ýÛæ¶À°”@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$876657fa-c27c-4a78-8908-cd3e274c4ef6*test2 ¥×液·”: ýÛ涂¸”@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3c795996-9912-4ba5-828e-9143227f3823*test2 ¥×æ¶ྔ: ýÛ涰¿”@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4f8ebc3c-3495-4a2f-b284-c5593ae2a31e*test2 ¥×涢Ɣ: ýÛæ¶òÆ”@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7036311e-3cd7-4f69-99c3-59e319e6f686*test2 ¥×æ¶ãÍ”: ýÛ涴Δ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c1a1c4b7-f8dd-4360-a914-d0087bfbfe84*test2 ¥×涥Ք: ýÛæ¶õÕ”@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b76aea49-a209-4f34-879d-e4a8ff4ce465*test2 ¥×æ¶ÓÜ”: ýÛ涣ݔ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9009b235-209b-4478-89ad-881540ec2f7a*test2 ¥×涟ä”: ýÛæ¶ïä”@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$eb02dd49-ce47-44c1-93f0-c001b1f9505a*test2 ¥×æ¶Âë”: ýÛæ¶ì”@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$81d3d646-833f-46e0-a535-b51c10cf0318*test2 ¥×涄ó”: ýÛæ¶Ôó”@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1887d273-130c-4d23-9332-fe917032f444*test2 ¥×æ¶Åþ”: ýÛ涕ÿ”@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a044a1e2-d289-4ceb-98f3-a8ab153fb9a6*test2 ¥×æ¶ó…•: ýÛæ¶Æ•@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e02f308d-472e-4c3f-9ecf-51bddb4c3e2e*test2 ¥×涿•: ýÛ涎•@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$db17e766-9806-4507-8165-75b20e701f18*test2 ¥×æ¶Ç••: ýÛ涗–•@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8790a2ce-f3e3-4c39-813f-1d9b44f0ae85*test2 ¥×涰•: ýÛ涞•@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8bfaf8bf-547c-408d-bef1-b489974da6ad*test2 ¥×æ¶ò¤•: ýÛæ¶Â¥•@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6817c9f1-7816-4113-8cf2-0a8c1deef1cf*test2 ¥×涠¬•: ýÛæ¶ú¬•@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b97074f7-ae03-4ac5-9b53-b2d7a1fc5952*test2 ¥×æ¶ܵ•: ýÛ涬¶•@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$39d9d814-295c-46aa-badf-3e301f4d7bcd*test2 ¥×æ¶ƽ•: ýÛ涖¾•@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c3af8169-918f-4875-a560-28be5e592bd5*test2 ¥×涒ŕ: ýÛæ¶âÅ•@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$79a69d91-1f1a-4026-88bc-1821fd0e2864*test2 ¥×æ¶ÞÌ•: ýÛ涮͕@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6e5ec6ba-cc59-4f29-9bc5-8320814910af*test2 ¥×涪ԕ: ýÛæ¶úÔ•@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ca4cd137-a43c-492f-a11f-40fcfb4bf4d9*test2 ¥×æ¶õÛ•: ýÛæ¶ÆÜ•@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3b6399cc-241c-45b8-9678-9f100571d168*test2 ¥×涷ã•: ýÛ涇ä•@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$75963354-15bd-43f8-ac4a-be206600d0f4*test2 ¥×æ¶ë•: ýÛæ¶Ýë•@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4435b485-a3a3-4b9e-95bd-94a293ee78e2*test2 ¥×æ¶Ùò•: ýÛ涩ó•@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$726fb8b1-a4c5-44a3-85b1-bf4e109e6160*test2 ¥×涛ú•: ýÛæ¶ëú•@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$62ff3387-2e09-4d2c-9ab8-16742995458f*test2 ¥×æ¶ð–: ýÛæ¶Ë‚–@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$32467e64-f85c-4d19-ae62-d2b3cd403a95*test2 ¥×涨‰–: ýÛæ¶ø‰–@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3dac3513-5177-4ca7-9006-37cbaf9bc6d4*test2 ¥×æ¶ê–: ýÛ涺‘–@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d2eb9390-b381-4ae8-9c85-033278ac7b6f*test2 ¥×涶˜–: ýÛ涆™–@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1a5f2df5-078d-4ff5-9b97-8d4bcbb216a1*test2 ¥×涂 –: ýÛæ¶Ò –@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$bd17bbb3-4d79-4249-9815-d15f96699ce2*test2 ¥×æ¶ç–: ýÛ涔¨–@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$905a9347-b216-4b88-929d-234585cb4c4b*test2 ¥×æ¶û®–: ýÛæ¶˯–@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7530fab8-95e8-4ea8-a5ae-b0400516f6da*test2 ¥×涩¶–: ýÛ涃·–@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5785ec5a-cfff-4450-953f-abf9156d6d47*test2 ¥×æ¶ÿ½–: ýÛæ¶Ͼ–@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1c1367ae-e733-4279-8198-8b593212babd*test2 ¥×涭Ŗ: ýÛæ¶ýÅ–@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c4a735fe-3b40-48fd-8256-dc5ba5ca10bf*test2 ¥×æ¶îÌ–: ýÛ涿͖@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1035d8e2-3ec6-4352-a67f-229db3f31e97*test2 ¥×涺Ԗ: ýÛ涔Ֆ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c06c75a2-3d91-448c-945c-053b62414a4c*test2 ¥×æ¶òÛ–: ýÛæ¶ÂÜ–@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b4cddf9b-ae5c-4ff4-b8aa-b7a9433d7c81*test2 ¥×涴ã–: ýÛ涄ä–@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$fab9cb7c-8695-4c29-a06c-702fafe47852*test2 ¥×涀ë–: ýÛæ¶Ðë–@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4db77f0a-aa43-4125-8f44-757291fa74b1*test2 ¥×æ¶Õò–: ýÛ润ó–@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$77361175-afe4-4f6c-8ff2-98475568f52f*test2 ¥×涡ú–: ýÛæ¶ñú–@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f3d8aa24-bd89-4789-be06-17bca5a3109b*test2 ¥×æ¶ã—: ýÛ涳‚—@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5f2943bb-14f3-4332-9559-1e4e5f78d21f*test2 ¥×涹‰—: ýÛ涉Š—@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9481c4fb-9f5e-46cb-a24d-f5e4cc722636*test2 ¥×涭‘—: ýÛæ¶ý‘—@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$bdc4b808-1874-4916-97b5-22f30ac24fc9*test2 ¥×æ¶嘗: ýÛ涵™—@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7813422e-d213-4001-adc2-a49364da3b3f*test2 ¥×涒 —: ýÛæ¶â —@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$34d9f6b3-bf22-42cb-ad45-bebc0276ebe9*test2 ¥×æ¶Þ§—: ýÛ涮¨—@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b3cdaec8-79f8-4261-9aef-46e4404853e4*test2 ¥×涪¯—: ýÛæ¶ú¯—@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1059f273-0cdb-464a-8ae8-b18420bbc5d0*test2 ¥×æ¶ö¶—: ýÛæ¶Æ·—@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$331965f1-ab7a-4d2e-8e90-c3c87da65cd1*test2 ¥×æ¶ྗ: ýÛ涺¿—@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$498b048b-2481-4d30-8105-d503daec8ab0*test2 ¥×æ¶ÀÆ—: ýÛæ¶Ç—@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ca39256c-b9b0-4631-aa0a-36ccbba58198*test2 ¥×涋Η: ýÛæ¶ÛΗ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8add34ea-7d73-4024-b92a-896a98755e00*test2 ¥×涹՗: ýÛ涓֗@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e5781ceb-3b02-4708-bdfa-aaee6635271d*test2 ¥×涅ݗ: ýÛæ¶ßÝ—@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d7977c37-73a7-4033-a9a3-c584ec87bb6e*test2 ¥×涽ä—: ýÛæ¶å—@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e8b92153-1e0c-460c-a89d-b77015abafcc*test2 ¥×涓ì—: ýÛæ¶ãì—@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$0adfcab1-27e2-488e-be1a-9c9892435967*test2 ¥×涗÷—: ýÛæ¶ç÷—@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5afd8f77-77eb-4169-8940-6aaa48b44d09*test2 ¥×æ¶Ïþ—: ýÛ涟ÿ—@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2a4f2b54-50d6-44d6-adac-5f93a3d4c870*test2 ¥×涥†˜: ýÛæ¶õ†˜@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e3ef7ed4-5f4d-4d93-aadc-b36f3296e30f*test2 ¥×æ¶Ó˜: ýÛ涭Ž˜@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a7f8fe8d-7716-472f-bbd9-aae6d3751d4f*test2 ¥×涔•˜: ýÛæ¶䕘@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b78d5763-8797-4b38-8dc2-0de009cdc6fe*test2 ¥×æ¶Âœ˜: ýÛ涒˜@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$84240059-bb41-4532-bc9d-52ee8d844d84*test2 ¥×æ¶ð£˜: ýÛæ¶ʤ˜@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f2dae9d9-2653-4007-976c-3f75bec2a798*test2 ¥×涓¯˜: ýÛæ¶㯘@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ed900a51-cfe4-4e55-965c-041eaede851a*test2 ¥×æ¶Þ¶˜: ýÛ涯·˜@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$08c74939-dae5-4e33-8070-71adb25dfb5d*test2 ¥×涂¾˜: ýÛæ¶Ò¾˜@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6a884a0b-afab-4093-9872-4978fe5825f9*test2 ¥×æ¶ìŘ: ýÛ涼Ƙ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f233a2ac-a110-4a4b-8fc4-9b6d361fc5c3*test2 ¥×涚͘: ýÛæ¶ê͘@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$20f2900e-3d69-447f-9c3b-bb4592b3d103*test2 ¥×æ¶ÈÔ˜: ýÛ涘՘@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6a16a147-0897-4fd6-8fbf-82c44b7bd8ec*test2 ¥×涉ܘ: ýÛæ¶Ùܘ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$91388e12-db68-4848-aed0-222da15ad006*test2 ¥×æ¶Õã˜: ýÛ涥ä˜@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$92fb3c89-6ee9-411e-a94e-e8f038f7f3bc*test2 ¥×涃ë˜: ýÛæ¶Óë˜@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$436ec1c4-c531-48c0-9d54-6776b4c0dc55*test2 ¥×æ¶Åò˜: ýÛ涕ó˜@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$755fa561-ff9f-40ab-b22f-bef559eca45e*test2 ¥×涹ú˜: ýÛ涉û˜@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c8e52a0b-86f0-4333-9de9-1f08e24244ba*test2 ¥×涎‚™: ýÛæ¶ß‚™@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$41992679-bc87-403c-b337-0a5bc200fc43*test2 ¥×涼‰™: ýÛ涌Š™@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9c6513ee-b250-4c84-9b1d-90addf43eba4*test2 ¥×æ¶þ™: ýÛæ¶Α™@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2439af17-58c4-400a-a5f4-d153ad9bb5e5*test2 ¥×æ¶Ô˜™: ýÛ涤™™@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f909c0bb-b952-4a3d-8db7-7fff7fbef361*test2 ¥×涂 ™: ýÛæ¶Ò ™@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f6152249-f6d4-496e-8933-1c7d2e1e8016*test2 ¥×涯§™: ýÛ涉¨™@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$36ac0c40-cf80-4558-92b5-7772d4b522da*test2 ¥×涅¯™: ýÛæ¶Õ¯™@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8c1551d5-73c0-4839-9b2f-a3bff65b2ec8*test2 ¥×涳¶™: ýÛ涃·™@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$25a05cb5-ef04-44d0-a12b-8da4ec101264*test2 ¥×æ¶ÿ½™: ýÛæ¶Ù¾™@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$beeb0f53-f53e-4926-b531-04169e3fb162*test2 ¥×æ¶ËÅ™: ýÛ涥ƙ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$30917036-d732-4b91-a1d5-2c45534d1986*test2 ¥×涪͙: ýÛæ¶ûÍ™@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9986d6a2-9cb2-4ad5-95ec-02cdf656d437*test2 ¥×æ¶ìÔ™: ýÛ涼ՙ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$21a37d68-34b9-4ed3-a67c-b8c2c8b8ad34*test2 ¥×涮ܙ: ýÛæ¶þÜ™@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$0208a0f7-a9cb-4457-bb14-137404c35a6f*test2 ¥×æ¶úã™: ýÛæ¶Êä™@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6f3876bb-65c4-4c0e-a408-4cd01093c15c*test2 ¥×涞ë™: ýÛæ¶øë™@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$076196be-3cdd-45e4-9c73-d82f9f8511ea*test2 ¥×æ¶ßò™: ýÛ涰ó™@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1fdc8f46-4e60-4737-b0fa-9722d7f6ebf7*test2 ¥×涫ú™: ýÛæ¶ûú™@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4cb72e12-254a-4715-90d2-a608f73e6ebb*test2 ¥×æ¶÷š: ýÛæ¶Ç‚š@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$92c491ba-39b0-4c0d-ac50-bca987eb267f*test2 ¥×涥‰š: ýÛæ¶õ‰š@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a3890be2-199f-4897-af16-7b54a9b6c314*test2 ¥×æ¶Ýš: ýÛ涷‘š@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9d0c85a0-ab11-4565-9622-fd887a30ff65*test2 ¥×涞˜š: ýÛæ¶@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9871628d-a2c9-4ff6-98ea-559e00e840f0*test2 ¥×æ¶àŸš: ýÛ涺 š@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d8604247-cb12-42a0-906d-46eeee8d29b5*test2 ¥×涢§š: ýÛæ¶ò§š@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f21199a3-e11d-4669-a26d-28619d4c6b10*test2 ¥×æ¶Юš: ýÛ涠¯š@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3c34680e-d659-4c32-8624-62114e8f9ea2*test2 ¥×涢¹š: ýÛæ¶ü¹š@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c2ca29fa-9475-444b-b03f-fff6450ba807*test2 ¥×æ¶ÚÀš: ýÛ涪Áš@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$bbcc949b-4920-4f50-838a-959178769e67*test2 ¥×润Ț: ýÛæ¶öÈš@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ebe3837f-93d4-4d63-810b-2d6734b02761*test2 ¥×æ¶ÔÏš: ýÛ涤К@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3c7efa18-5e7e-4ee4-a5d7-93a29c54b63c*test2 ¥×æ¶ך: ýÛæ¶Üך@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$97f583dc-e7f3-4ef9-b944-9c87a5c097a3*test2 ¥×涹ޚ: ýÛ涉ߚ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$90807325-f2ad-48d4-aede-c04d9459c7c9*test2 ¥×æ¶çåš: ýÛ涷æš@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d9743afc-7f0c-4b18-beb5-bc3996076ec0*test2 ¥×涟íš: ýÛæ¶ïíš@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4ca09ff2-7f80-4fe3-a686-e150e86ce102*test2 ¥×æ¶àôš: ýÛ涱õš@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ab846f57-de2c-46fd-9e66-c66aa9c4aff0*test2 ¥×æ¶Êüš: ýÛ涚ýš@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$20e1d1e6-000f-47d8-b0a8-b0b16dbd239b*test2 ¥×涌„›: ýÛæ¶Ü„›@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$69e9fc53-371b-4f34-9937-d8501aefb9c6*test2 ¥×æ¶Ø‹›: ýÛ涨Œ›@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a8cfbd1d-2937-43d3-bd16-6991805ff235*test2 ¥×涆“›: ýÛæ¶Ö“›@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$bf58a74f-a808-4312-bbe2-234d1e01deb7*test2 ¥×涽š›: ýÛ涎››@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a574c7ef-0bc4-4ba7-a97e-9832859c59b4*test2 ¥×æ¶ÿ¡›: ýÛæ¶Ï¢›@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$ad7ac1a0-b46c-430a-8337-d606e7802be9*test2 ¥×涷©›: ýÛ涇ª›@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$79b149b0-d89d-4fbe-9f42-7201cc7b08a7*test2 ¥×涱›: ýÛæ¶ݱ›@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a7dfdb5b-b5a1-4ce7-b57f-0c726df43acf*test2 ¥×涻¸›: ýÛ涕¹›@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$eef71d0c-03f8-4378-8ccb-feb7a8d90191*test2 ¥×涹À›: ýÛ涉Á›@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a49caa60-fec2-4c62-bf25-7e6aa7f02525*test2 ¥×æ¶æÇ›: ýÛæ¶ÁÈ›@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6be9a36f-9f2c-494b-be38-4f7d34151147*test2 ¥×涞ϛ: ýÛæ¶îÏ›@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5f9df3b2-f4a8-402f-8c64-f9de2f2e7878*test2 ¥×æ¶çÙ›: ýÛ涷ڛ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$f7303b60-901b-42b3-bc1d-cced8ed13348*test2 ¥×涞á›: ýÛæ¶ïá›@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$43471593-6c5a-4a1b-b64d-05539249bb36*test2 ¥×æ¶Ìè›: ýÛ涜é›@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b360a54b-b4ba-4b37-910b-2acc70fa8bff*test2 ¥×涢ð›: ýÛæ¶òð›@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$112f7b75-4a47-4ca5-a388-fcf96990ab3d*test2 ¥×æ¶Ð÷›: ýÛ涠ø›@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9542c834-dbcf-4a9b-81b1-161f070b784d*test2 ¥×消ÿ›: ýÛæ¶âÿ›@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1851f57d-28f5-4606-a073-553b2e4bb1c1*test2 ¥×涵†œ: ýÛ涅‡œ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$7be30943-405c-43aa-ba70-e2b960f9f773*test2 ¥×涕Žœ: ýÛæ¶厜@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3639b5cc-40d5-4be7-94c8-c7e973101c88*test2 ¥×æ¶וœ: ýÛ涧–œ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$85eb68e8-4e64-41cf-8732-cf5f0941ac8d*test2 ¥×涅œ: ýÛæ¶Õœ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$fe45b2bf-6371-447d-877f-b3216930523c*test2 ¥×涨¤œ: ýÛ涃¥œ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b7e3e592-24b5-4d3d-ad5a-ba18f191bc28*test2 ¥×æ¶ô«œ: ýÛæ¶άœ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9f28c416-d88e-4150-8b60-09ccc26bc248*test2 ¥×涬³œ: ýÛæ¶ü³œ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e6478bc0-a4d3-4ad7-913e-40573503c5bc*test2 ¥×æ¶: ýÛ涾»œ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b407acdf-5bb2-47ca-b742-0a2b8f4f24a7*test2 ¥×涰œ: ýÛ涊Ü@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c8f09386-1bb7-4301-92fb-613805b9d217*test2 ¥×æ¶ÝÉœ: ýÛ涮ʜ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9fd944a6-46dc-4f44-a4a2-f2bede0d8f3c*test2 ¥×涟ќ: ýÛæ¶ùÑœ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4518ddc9-098e-4e65-a3e2-8c28e60810ce*test2 ¥×æ¶×Øœ: ýÛ涧ٜ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$236fbdf7-ce4a-4464-a298-03a9a09a05ad*test2 ¥×æ¶àœ: ýÛæ¶ßàœ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c28f0ea3-7536-4f76-84e5-0b7dccca3a98*test2 ¥×æ¶Ççœ: ýÛ涗èœ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$73b8508e-cb84-464d-8898-dc074ec8d192*test2 ¥×æ¶ôîœ: ýÛæ¶Îïœ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$94618a6e-c479-4ddc-bf84-079e09358e5a*test2 ¥×æ¶ãøœ: ýÛ涽ùœ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$4a2d290b-ed25-4f30-a250-44af9cb25c68*test2 ¥×涚€: ýÛæ¶ë€@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8805cbae-e50a-4be1-9583-35a51cff4de2*test2 ¥×æ¶æ‡: ýÛ涶ˆ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8f05358f-a9a4-4f1c-bac0-b8a981543145*test2 ¥×涞: ýÛæ¶ø@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$5e716201-778c-4007-880d-a9d51d516ee8*test2 ¥×æ¶Ö–: ýÛ润—@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$27a475ee-ff46-4f32-a432-df671d207f9d*test2 ¥×涢ž: ýÛæ¶òž@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$417316cf-dcfb-4848-bbfc-d7cb5cd05b47*test2 ¥×æ¶÷¥: ýÛæ¶Ȧ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$cf75aedf-149b-4741-91b8-8002e716b066*test2 ¥×æ¶Í­: ýÛ涮@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c44ba02b-6db1-433a-abf4-6619db20eb28*test2 ¥×涅µ: ýÛæ¶Õµ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d310b3ee-2a05-46ec-9a1f-a0793b29373d*test2 ¥×涳¼: ýÛ涃½@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6e3d8d05-d3fb-4f4d-adfc-f489ecd6b235*test2 ¥×æ¶õÃ: ýÛæ¶ÏÄ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$b95fb8a5-b0e1-4595-81b7-9760318c05d4*test2 ¥×æ¶ÀË: ýÛ涑Ì@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$eabc5572-13c1-4892-b30d-b278a6e7495d*test2 ¥×æ¶øÒ: ýÛæ¶ÈÓ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$df655fa3-9cf5-426f-8a51-13ba1061e226*test2 ¥×æ¶ØÚ: ýÛ液Û@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2e9d0868-48bd-4ff5-a837-4bd8b77caf09*test2 ¥×æ¶êâ: ýÛ涺ã@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$3995f6aa-151d-4c53-878b-a23cec8efdc5*test2 ¥×涢ê: ýÛæ¶òê@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$38d0ebb8-fa57-40c1-88f6-51c1eeb860ba*test2 ¥×æ¶øñ: ýÛæ¶Èò@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$aebbc965-c4d5-4c1c-b6ca-b3c8f9e996da*test2 ¥×涥ù: ýÛæ¶öù@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$9cbdd4ec-b911-4b4c-ab09-cf4c40050f52*test2 ¥×涅ž: ýÛæ¶Õž@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$a775047e-b06e-41da-99bf-097a3c9b348c*test2 ¥×涳ˆž: ýÛ涉ž@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$2d890603-0d4b-43df-8871-7b95c6991034*test2 ¥×æ¶ëž: ýÛ涻ž@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$61fe95f1-e1b9-47ae-be8a-3a5a1f47ba66*test2 ¥×æ¶Ë—ž: ýÛ涛˜ž@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$10258b4c-95ca-4bbe-a4b2-97d6f7106e4b*test2 ¥×涂Ÿž: ýÛæ¶ÝŸž@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$8e512d2d-a630-42db-9861-dacacf6618ae*test2 ¥×涺¦ž: ýÛ涊§ž@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$e476cc03-c401-401f-9d3a-eea1429e14e5*test2 ¥×æ¶è­ž: ýÛ涸®ž@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$d2c8f91b-e87c-4908-b5ed-0447f48f135b*test2 ¥×涴µž: ýÛ涄¶ž@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$35d8c56a-f1e5-4f25-8d3a-874a436e00ea*test2 ¥×æ¶ö¼ž: ýÛæ¶ƽž@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$70d69adc-c9fd-49c2-becc-66fe5a1d3295*test2 ¥×涣Ğ: ýÛæ¶þÄž@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$11a9b2cf-f71e-4f0b-b9e6-2b54b8bee4e1*test2 ¥×æ¶ùËž: ýÛæ¶ÉÌž@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1cd65b71-171a-46e8-b415-eaee757ea9b6*test2 ¥×涻Ӟ: ýÛ涋Ԟ@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$1fb2b649-c12a-4f6a-8489-b0adf7cbf8c4*test2 ¥×æ¶ýÚž: ýÛæ¶ÍÛž@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$039735c3-1b27-48fc-b4e7-703cabbc2048*test2 ¥×æ¶çâž: ýÛ涷ãž@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$6f8f5234-4e90-4fa8-9fd5-10d40568b0fb*test2 ¥×涨êž: ýÛ涃ëž@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$c725bf46-c030-423a-a7c2-5ef162203d98*test2 ¥×æ¶Öñž: ýÛ润òž@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace— + vParquet3$044a2af7-c788-4a98-846e-f83467186bb6*test2 ¥×涎ùž: ýÛæ¶Þùž@ +H¹`PX`¡hÄËxô€Ÿ{Š  namespaceŠ  http.methodŠ  namespace \ No newline at end of file diff --git a/tempodb/backend/testdata/test/index.json.gz b/tempodb/backend/testdata/test/index.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..59ac8563e8985fcf2d9146a7e3bab63ef47ebd8b GIT binary patch literal 34699 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 O{{sLxl3aLAvIYR&ovVBR literal 0 HcmV?d00001 diff --git a/tempodb/compaction_block_selector.go b/tempodb/compaction_block_selector.go index febf6b27d76..062e6e896c1 100644 --- a/tempodb/compaction_block_selector.go +++ b/tempodb/compaction_block_selector.go @@ -164,7 +164,7 @@ func (twbs *timeWindowBlockSelector) BlocksToCompact() ([]*backend.BlockMeta, st func totalObjects(entries []timeWindowBlockEntry) int { totalObjects := 0 for _, b := range entries { - totalObjects += b.meta.TotalObjects + totalObjects += int(b.meta.TotalObjects) } return totalObjects } @@ -172,7 +172,7 @@ func totalObjects(entries []timeWindowBlockEntry) int { func totalSize(entries []timeWindowBlockEntry) uint64 { sz := uint64(0) for _, b := range entries { - sz += b.meta.Size + sz += b.meta.Size_ } return sz } diff --git a/tempodb/compaction_block_selector_test.go b/tempodb/compaction_block_selector_test.go index ffba3f5b7de..7f225a6b20d 100644 --- a/tempodb/compaction_block_selector_test.go +++ b/tempodb/compaction_block_selector_test.go @@ -5,7 +5,8 @@ import ( "testing" "time" - "github.com/google/uuid" + google_uuid "github.com/google/uuid" + "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/stretchr/testify/assert" ) @@ -40,21 +41,21 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "only two", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, EndTime: now, }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, EndTime: now, }, }, @@ -64,17 +65,17 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "choose smallest two", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, TotalObjects: 0, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, TotalObjects: 1, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, TotalObjects: 0, EndTime: now, }, @@ -82,12 +83,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { maxInputBlocks: 2, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, TotalObjects: 0, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, TotalObjects: 0, EndTime: now, }, @@ -98,40 +99,40 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "different windows", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, EndTime: now.Add(-timeWindow), }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, EndTime: now.Add(-timeWindow), }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, EndTime: now, }, }, expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 0), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, EndTime: now.Add(-timeWindow), }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, EndTime: now.Add(-timeWindow), }, }, @@ -141,22 +142,22 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "different sizes", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, EndTime: now, TotalObjects: 15, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, EndTime: now, TotalObjects: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, EndTime: now, TotalObjects: 3, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, EndTime: now, TotalObjects: 12, }, @@ -164,12 +165,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { maxInputBlocks: 2, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, EndTime: now, TotalObjects: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, EndTime: now, TotalObjects: 3, }, @@ -177,12 +178,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 0), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, EndTime: now, TotalObjects: 12, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, EndTime: now, TotalObjects: 15, }, @@ -193,43 +194,43 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "different compaction lvls", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, EndTime: now, }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, EndTime: now, }, }, expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 0), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, EndTime: now, CompactionLevel: 1, }, @@ -240,48 +241,48 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "active time window vs not", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, EndTime: now.Add(-activeWindowDuration - time.Minute), CompactionLevel: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, EndTime: now.Add(-activeWindowDuration - time.Minute), CompactionLevel: 0, }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, EndTime: now, }, }, expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 0), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, EndTime: now.Add(-activeWindowDuration - time.Minute), CompactionLevel: 0, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, EndTime: now.Add(-activeWindowDuration - time.Minute), CompactionLevel: 1, }, @@ -292,50 +293,50 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "choose lowest compaction level", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, EndTime: now.Add(-timeWindow), }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000005"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000005")}, EndTime: now.Add(-timeWindow), }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, EndTime: now, }, }, expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 0), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, EndTime: now.Add(-timeWindow), }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000005"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000005")}, EndTime: now.Add(-timeWindow), }, }, @@ -345,11 +346,11 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "doesn't choose across time windows", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, EndTime: now.Add(-timeWindow), }, }, @@ -362,12 +363,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "doesn't exceed max compaction objects", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, TotalObjects: 99, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, TotalObjects: 2, EndTime: now, }, @@ -381,13 +382,13 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "doesn't exceed max block size", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), - Size: 50, + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + Size_: 50, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), - Size: 51, + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + Size_: 51, EndTime: now, }, }, @@ -401,29 +402,29 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "Returns as many blocks as possible without exceeding max compaction objects", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, TotalObjects: 50, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, TotalObjects: 50, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, TotalObjects: 50, EndTime: now, }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, TotalObjects: 50, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, TotalObjects: 50, EndTime: now, }, @@ -437,30 +438,30 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { maxBlockBytes: 100, blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), - Size: 50, + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + Size_: 50, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), - Size: 50, + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + Size_: 50, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), - Size: 1, + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, + Size_: 1, EndTime: now, }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), - Size: 50, + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + Size_: 50, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), - Size: 50, + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + Size_: 50, EndTime: now, }, }, @@ -474,44 +475,44 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { maxInputBlocks: 3, blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, EndTime: now, TotalObjects: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, EndTime: now, TotalObjects: 2, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, EndTime: now, TotalObjects: 3, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, EndTime: now, TotalObjects: 4, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000005"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000005")}, EndTime: now, TotalObjects: 5, }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, EndTime: now, TotalObjects: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, EndTime: now, TotalObjects: 2, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, EndTime: now, TotalObjects: 3, }, @@ -519,12 +520,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 0), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, EndTime: now, TotalObjects: 4, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000005"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000005")}, EndTime: now, TotalObjects: 5, }, @@ -535,11 +536,11 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "honors minimum block count", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, EndTime: now, }, }, @@ -554,22 +555,22 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "can choose blocks not at the lowest compaction level", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, EndTime: now, CompactionLevel: 0, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, EndTime: now, CompactionLevel: 1, }, @@ -578,17 +579,17 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { maxInputBlocks: 3, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, EndTime: now, CompactionLevel: 1, }, @@ -601,12 +602,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "doesn't select blocks in last active window", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, EndTime: now.Add(-activeWindowDuration), CompactionLevel: 0, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, EndTime: now.Add(-activeWindowDuration), CompactionLevel: 0, }, @@ -616,12 +617,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "don't compact across dataEncodings", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, EndTime: now, DataEncoding: "bar", }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, EndTime: now, DataEncoding: "foo", }, @@ -632,12 +633,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "ensures blocks of different versions are not compacted", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, EndTime: now, Version: "v2", }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, EndTime: now, Version: "vParquet3", }, @@ -651,34 +652,34 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "ensures blocks of the same version are compacted", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, EndTime: now, Version: "v2", }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, EndTime: now, Version: "vParquet3", }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, EndTime: now, Version: "v2", }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, EndTime: now, Version: "vParquet3", }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, EndTime: now, Version: "v2", }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, EndTime: now, Version: "v2", }, @@ -686,12 +687,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 0), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, EndTime: now, Version: "vParquet3", }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, EndTime: now, Version: "vParquet3", }, @@ -702,28 +703,28 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "blocks with different dedicated columns are not selected together", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, EndTime: now, DedicatedColumns: backend.DedicatedColumns{ {Scope: "span", Name: "foo", Type: "int"}, }, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, EndTime: now, DedicatedColumns: backend.DedicatedColumns{ {Scope: "span", Name: "foo", Type: "string"}, }, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, EndTime: now, DedicatedColumns: backend.DedicatedColumns{ {Scope: "span", Name: "foo", Type: "int"}, }, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, EndTime: now, DedicatedColumns: backend.DedicatedColumns{ {Scope: "span", Name: "foo", Type: "string"}, @@ -732,14 +733,14 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { }, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, EndTime: now, DedicatedColumns: backend.DedicatedColumns{ {Scope: "span", Name: "foo", Type: "int"}, }, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, EndTime: now, DedicatedColumns: backend.DedicatedColumns{ {Scope: "span", Name: "foo", Type: "int"}, @@ -749,14 +750,14 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 0), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, EndTime: now, DedicatedColumns: backend.DedicatedColumns{ {Scope: "span", Name: "foo", Type: "string"}, }, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, EndTime: now, DedicatedColumns: backend.DedicatedColumns{ {Scope: "span", Name: "foo", Type: "string"}, @@ -769,34 +770,34 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "blocks are grouped by replication factor", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, EndTime: now, ReplicationFactor: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, EndTime: now, ReplicationFactor: 3, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, EndTime: now, ReplicationFactor: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, EndTime: now, ReplicationFactor: 3, }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, EndTime: now, ReplicationFactor: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, EndTime: now, ReplicationFactor: 1, }, @@ -804,12 +805,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 1), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, EndTime: now, ReplicationFactor: 3, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, EndTime: now, ReplicationFactor: 3, }, diff --git a/tempodb/compactor.go b/tempodb/compactor.go index f6958ad8dd5..5fabd0cd845 100644 --- a/tempodb/compactor.go +++ b/tempodb/compactor.go @@ -198,10 +198,10 @@ func (rw *readerWriter) compact(ctx context.Context, blockMetas []*backend.Block var totalRecords int for _, blockMeta := range blockMetas { level.Info(rw.logger).Log("msg", "compacting block", "block", fmt.Sprintf("%+v", blockMeta)) - totalRecords += blockMeta.TotalObjects + totalRecords += int(blockMeta.TotalObjects) // Make sure block still exists - _, err = rw.r.BlockMeta(ctx, blockMeta.BlockID, tenantID) + _, err = rw.r.BlockMeta(ctx, blockMeta.BlockID.UUID, tenantID) if err != nil { return err } @@ -283,7 +283,7 @@ func markCompacted(rw *readerWriter, tenantID string, oldBlocks, newBlocks []*ba var errCount int for _, meta := range oldBlocks { // Mark in the backend - if err := rw.c.MarkBlockCompacted(meta.BlockID, tenantID); err != nil { + if err := rw.c.MarkBlockCompacted(meta.BlockID.UUID, tenantID); err != nil { errCount++ level.Error(rw.logger).Log("msg", "unable to mark block compacted", "blockID", meta.BlockID, "tenantID", tenantID, "err", err) metricCompactionErrors.Inc() @@ -330,8 +330,8 @@ func compactionLevelForBlocks(blockMetas []*backend.BlockMeta) uint8 { level := uint8(0) for _, m := range blockMetas { - if m.CompactionLevel > level { - level = m.CompactionLevel + if m.CompactionLevel > uint32(level) { + level = uint8(m.CompactionLevel) } } diff --git a/tempodb/compactor_test.go b/tempodb/compactor_test.go index c5cb055e3c2..e26cb118125 100644 --- a/tempodb/compactor_test.go +++ b/tempodb/compactor_test.go @@ -12,7 +12,7 @@ import ( "github.com/go-kit/log" proto "github.com/gogo/protobuf/proto" - "github.com/google/uuid" + google_uuid "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -21,6 +21,7 @@ import ( v1 "github.com/grafana/tempo/pkg/model/v1" "github.com/grafana/tempo/pkg/tempopb" "github.com/grafana/tempo/pkg/util/test" + "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/backend/local" "github.com/grafana/tempo/tempodb/blocklist" @@ -131,7 +132,7 @@ func testCompactionRoundtrip(t *testing.T, targetBlockVersion string) { allIds := make([]common.ID, 0, blockCount*recordCount) for i := 0; i < blockCount; i++ { - blockID := uuid.New() + blockID := uuid.UUID{UUID: google_uuid.New()} meta := &backend.BlockMeta{BlockID: blockID, TenantID: testTenantID, DataEncoding: model.CurrentEncoding} head, err := wal.NewBlock(meta, model.CurrentEncoding) require.NoError(t, err) @@ -154,7 +155,7 @@ func testCompactionRoundtrip(t *testing.T, targetBlockVersion string) { expectedBlockCount := blockCount expectedCompactedCount := 0 - checkBlocklists(t, uuid.Nil, expectedBlockCount, expectedCompactedCount, rw) + checkBlocklists(t, google_uuid.Nil, expectedBlockCount, expectedCompactedCount, rw) blocksPerCompaction := (inputBlocks - outputBlocks) @@ -178,7 +179,7 @@ func testCompactionRoundtrip(t *testing.T, targetBlockVersion string) { expectedBlockCount -= blocksPerCompaction expectedCompactedCount += inputBlocks - checkBlocklists(t, uuid.Nil, expectedBlockCount, expectedCompactedCount, rw) + checkBlocklists(t, google_uuid.Nil, expectedBlockCount, expectedCompactedCount, rw) } require.Equal(t, expectedCompactions, compactions) @@ -186,7 +187,7 @@ func testCompactionRoundtrip(t *testing.T, targetBlockVersion string) { // do we have the right number of records var records int for _, meta := range rw.blocklist.Metas(testTenantID) { - records += meta.TotalObjects + records += int(meta.TotalObjects) } require.Equal(t, blockCount*recordCount, records) @@ -303,7 +304,7 @@ func testSameIDCompaction(t *testing.T, targetBlockVersion string) { // and write them to different blocks for i := 0; i < blockCount; i++ { - blockID := uuid.New() + blockID := uuid.UUID{UUID: google_uuid.New()} meta := &backend.BlockMeta{BlockID: blockID, TenantID: testTenantID, DataEncoding: v1.Encoding} head, err := wal.NewBlock(meta, v1.Encoding) require.NoError(t, err) @@ -325,7 +326,7 @@ func testSameIDCompaction(t *testing.T, targetBlockVersion string) { rw := r.(*readerWriter) // check blocklists, force compaction and check again - checkBlocklists(t, uuid.Nil, blockCount, 0, rw) + checkBlocklists(t, google_uuid.Nil, blockCount, 0, rw) var blocks []*backend.BlockMeta list := rw.blocklist.Metas(testTenantID) @@ -339,7 +340,7 @@ func testSameIDCompaction(t *testing.T, targetBlockVersion string) { err = rw.compact(ctx, blocks, testTenantID) require.NoError(t, err) - checkBlocklists(t, uuid.Nil, 1, blockCount, rw) + checkBlocklists(t, google_uuid.Nil, 1, blockCount, rw) // force clear compacted blocks to guarantee that we're only querying the new blocks that went through the combiner metas := rw.blocklist.Metas(testTenantID) @@ -426,8 +427,8 @@ func TestCompactionUpdatesBlocklist(t *testing.T) { // New blocklist contains 1 compacted block with everything blocks := rw.blocklist.Metas(testTenantID) require.Equal(t, 1, len(blocks)) - require.Equal(t, uint8(1), blocks[0].CompactionLevel) - require.Equal(t, blockCount*recordCount, blocks[0].TotalObjects) + require.Equal(t, uint32(1), blocks[0].CompactionLevel) + require.Equal(t, int32(blockCount*recordCount), blocks[0].TotalObjects) // Compacted list contains all old blocks require.Equal(t, blockCount, len(rw.blocklist.CompactedMetas(testTenantID))) @@ -651,7 +652,7 @@ func testCompactionHonorsBlockStartEndTimes(t *testing.T, targetBlockVersion str // New blocklist contains 1 compacted block with min start and max end blocks := rw.blocklist.Metas(testTenantID) require.Equal(t, 1, len(blocks)) - require.Equal(t, uint8(1), blocks[0].CompactionLevel) + require.Equal(t, uint32(1), blocks[0].CompactionLevel) require.Equal(t, 100, int(blocks[0].StartTime.Unix())) require.Equal(t, 107, int(blocks[0].EndTime.Unix())) } @@ -702,7 +703,7 @@ func testCompactionDropsTraces(t *testing.T, targetBlockVersion string) { allIDs := make([]common.ID, 0, recordCount) // write a bunch of dummy data - blockID := uuid.New() + blockID := uuid.UUID{UUID: google_uuid.New()} meta := &backend.BlockMeta{BlockID: blockID, TenantID: testTenantID, DataEncoding: v1.Encoding} head, err := wal.NewBlock(meta, v1.Encoding) require.NoError(t, err) @@ -789,7 +790,7 @@ func cutTestBlockWithTraces(t testing.TB, w Writer, tenantID string, data []test wal := w.WAL() - meta := &backend.BlockMeta{BlockID: uuid.New(), TenantID: testTenantID} + meta := &backend.BlockMeta{BlockID: uuid.UUID{UUID: google_uuid.New()}, TenantID: testTenantID} head, err := wal.NewBlock(meta, model.CurrentEncoding) require.NoError(t, err) @@ -809,7 +810,7 @@ func cutTestBlocks(t testing.TB, w Writer, tenantID string, blockCount int, reco wal := w.WAL() for i := 0; i < blockCount; i++ { - meta := &backend.BlockMeta{BlockID: uuid.New(), TenantID: tenantID} + meta := &backend.BlockMeta{BlockID: uuid.UUID{UUID: google_uuid.New()}, TenantID: tenantID} head, err := wal.NewBlock(meta, model.CurrentEncoding) require.NoError(t, err) diff --git a/tempodb/encoding/v2/backend_block.go b/tempodb/encoding/v2/backend_block.go index c0e7c8025fe..50c230b581a 100644 --- a/tempodb/encoding/v2/backend_block.go +++ b/tempodb/encoding/v2/backend_block.go @@ -55,7 +55,7 @@ func (b *BackendBlock) find(ctx context.Context, id common.ID) ([]byte, error) { tenantID := b.meta.TenantID nameBloom := common.BloomName(shardKey) - bloomBytes, err := b.reader.Read(ctx, nameBloom, blockID, tenantID, &backend.CacheInfo{ + bloomBytes, err := b.reader.Read(ctx, nameBloom, blockID.UUID, tenantID, &backend.CacheInfo{ Meta: b.meta, Role: cache.RoleBloom, }) diff --git a/tempodb/encoding/v2/backend_block_test.go b/tempodb/encoding/v2/backend_block_test.go index 23356895b3c..efb19d3e348 100644 --- a/tempodb/encoding/v2/backend_block_test.go +++ b/tempodb/encoding/v2/backend_block_test.go @@ -52,7 +52,7 @@ func testLegacyBlock(t *testing.T, ids [][]byte, objs [][]byte, meta *backend.Bl require.NoError(t, err, "error creating backend") reader := backend.NewReader(r) - meta, err = reader.BlockMeta(context.Background(), meta.BlockID, meta.TenantID) + meta, err = reader.BlockMeta(context.Background(), meta.BlockID.UUID, meta.TenantID) require.NoError(t, err, "error retrieving meta") backendBlock, err := NewBackendBlock(meta, reader) diff --git a/tempodb/encoding/v2/block.go b/tempodb/encoding/v2/block.go index e2de0c2ff68..8a7cf3bdd6c 100644 --- a/tempodb/encoding/v2/block.go +++ b/tempodb/encoding/v2/block.go @@ -17,7 +17,7 @@ func writeBlockMeta(ctx context.Context, w backend.Writer, meta *backend.BlockMe } // index - err = w.Write(ctx, common.NameIndex, meta.BlockID, meta.TenantID, indexBytes, nil) + err = w.Write(ctx, common.NameIndex, meta.BlockID.UUID, meta.TenantID, indexBytes, nil) if err != nil { return fmt.Errorf("unexpected error writing index: %w", err) } @@ -29,7 +29,7 @@ func writeBlockMeta(ctx context.Context, w backend.Writer, meta *backend.BlockMe // bloom for i, bloom := range blooms { nameBloom := common.BloomName(i) - err := w.Write(ctx, nameBloom, meta.BlockID, meta.TenantID, bloom, cacheInfo) + err := w.Write(ctx, nameBloom, meta.BlockID.UUID, meta.TenantID, bloom, cacheInfo) if err != nil { return fmt.Errorf("unexpected error writing bloom-%d: %w", i, err) } @@ -46,20 +46,20 @@ func writeBlockMeta(ctx context.Context, w backend.Writer, meta *backend.BlockMe // appendBlockData appends the bytes passed to the block data func appendBlockData(ctx context.Context, w backend.Writer, meta *backend.BlockMeta, tracker backend.AppendTracker, buffer []byte) (backend.AppendTracker, error) { - return w.Append(ctx, common.NameObjects, meta.BlockID, meta.TenantID, tracker, buffer) + return w.Append(ctx, common.NameObjects, meta.BlockID.UUID, meta.TenantID, tracker, buffer) } // CopyBlock copies a block from one backend to another. It is done at a low level, all encoding/formatting is preserved. func CopyBlock(ctx context.Context, srcMeta, destMeta *backend.BlockMeta, src backend.Reader, dest backend.Writer) error { // Copy streams, efficient but can't cache. copyStream := func(name string) error { - reader, size, err := src.StreamReader(ctx, name, srcMeta.BlockID, srcMeta.TenantID) + reader, size, err := src.StreamReader(ctx, name, srcMeta.BlockID.UUID, srcMeta.TenantID) if err != nil { return fmt.Errorf("error reading %s: %w", name, err) } defer reader.Close() - return dest.StreamWriter(ctx, name, destMeta.BlockID, destMeta.TenantID, reader, size) + return dest.StreamWriter(ctx, name, destMeta.BlockID.UUID, destMeta.TenantID, reader, size) } cacheInfo := &backend.CacheInfo{ @@ -69,13 +69,13 @@ func CopyBlock(ctx context.Context, srcMeta, destMeta *backend.BlockMeta, src ba // Read entire object and attempt to cache cpyBloom := func(name string) error { cacheInfo.Meta = srcMeta - b, err := src.Read(ctx, name, srcMeta.BlockID, srcMeta.TenantID, cacheInfo) + b, err := src.Read(ctx, name, srcMeta.BlockID.UUID, srcMeta.TenantID, cacheInfo) if err != nil { return fmt.Errorf("error reading %s: %w", name, err) } cacheInfo.Meta = destMeta - return dest.Write(ctx, name, destMeta.BlockID, destMeta.TenantID, b, cacheInfo) + return dest.Write(ctx, name, destMeta.BlockID.UUID, destMeta.TenantID, b, cacheInfo) } // Data diff --git a/tempodb/encoding/v2/compactor.go b/tempodb/encoding/v2/compactor.go index d037dce6b42..1f8f9f055a3 100644 --- a/tempodb/encoding/v2/compactor.go +++ b/tempodb/encoding/v2/compactor.go @@ -38,8 +38,8 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, } }() - var compactionLevel uint8 - var totalRecords int + var compactionLevel uint32 + var totalRecords int32 for _, blockMeta := range inputs { totalRecords += blockMeta.TotalObjects @@ -63,7 +63,7 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, nextCompactionLevel := compactionLevel + 1 - recordsPerBlock := (totalRecords / int(c.opts.OutputBlocks)) + recordsPerBlock := (totalRecords / int32(c.opts.OutputBlocks)) combiner := c.opts.Combiner if combiner == nil { @@ -92,7 +92,7 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, // make a new block if necessary if currentBlock == nil { - currentBlock, err = NewStreamingBlock(&c.opts.BlockConfig, uuid.New(), tenantID, inputs, recordsPerBlock) + currentBlock, err = NewStreamingBlock(&c.opts.BlockConfig, uuid.New(), tenantID, inputs, int(recordsPerBlock)) if err != nil { return nil, fmt.Errorf("error making new compacted block: %w", err) } @@ -115,7 +115,7 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, } // ship block to backend if done - if currentBlock.Length() >= recordsPerBlock { + if currentBlock.Length() >= int(recordsPerBlock) { err = c.finishBlock(ctx, w, tracker, currentBlock, l) if err != nil { return nil, fmt.Errorf("error shipping block to backend: %w", err) diff --git a/tempodb/encoding/v2/create_block.go b/tempodb/encoding/v2/create_block.go index f72dcded1c4..240628009d8 100644 --- a/tempodb/encoding/v2/create_block.go +++ b/tempodb/encoding/v2/create_block.go @@ -19,7 +19,7 @@ func CreateBlock(ctx context.Context, cfg *common.BlockConfig, meta *backend.Blo meta.DataEncoding = model.CurrentEncoding } - newBlock, err := NewStreamingBlock(cfg, meta.BlockID, meta.TenantID, []*backend.BlockMeta{meta}, meta.TotalObjects) + newBlock, err := NewStreamingBlock(cfg, meta.BlockID.UUID, meta.TenantID, []*backend.BlockMeta{meta}, int(meta.TotalObjects)) if err != nil { return nil, fmt.Errorf("error creating streaming block: %w", err) } diff --git a/tempodb/encoding/v2/streaming_block.go b/tempodb/encoding/v2/streaming_block.go index b499548745e..313969466a3 100644 --- a/tempodb/encoding/v2/streaming_block.go +++ b/tempodb/encoding/v2/streaming_block.go @@ -144,13 +144,13 @@ func (c *StreamingBlock) Complete(ctx context.Context, tracker backend.AppendTra meta.TotalRecords = uint32(len(records)) // casting meta.IndexPageSize = uint32(c.cfg.IndexPageSizeBytes) - meta.BloomShardCount = uint16(c.bloom.GetShardCount()) + meta.BloomShardCount = uint32(c.bloom.GetShardCount()) return bytesFlushed, writeBlockMeta(ctx, w, meta, indexBytes, c.bloom) } func (c *StreamingBlock) BlockMeta() *backend.BlockMeta { meta := c.meta - meta.Size = c.appender.DataLength() + meta.Size_ = c.appender.DataLength() return meta } diff --git a/tempodb/encoding/v2/streaming_block_test.go b/tempodb/encoding/v2/streaming_block_test.go index c6f58583f09..71f0d0b25d0 100644 --- a/tempodb/encoding/v2/streaming_block_test.go +++ b/tempodb/encoding/v2/streaming_block_test.go @@ -115,8 +115,8 @@ func TestStreamingBlockAddObject(t *testing.T) { assert.Equal(t, time.Unix(10000, 0), meta.StartTime) assert.Equal(t, time.Unix(25000, 0), meta.EndTime) assert.Equal(t, testTenantID, meta.TenantID) - assert.Equal(t, numObjects, meta.TotalObjects) - assert.Greater(t, meta.Size, uint64(0)) + assert.Equal(t, int32(numObjects), meta.TotalObjects) + assert.Greater(t, meta.Size_, uint64(0)) assert.Greater(t, cb.bloom.GetShardCount(), 0) // bloom @@ -244,7 +244,7 @@ func streamingBlock(t *testing.T, cfg *common.BlockConfig, w backend.Writer) (*S originatingMeta.StartTime = time.Now().Add(-5 * time.Minute) originatingMeta.EndTime = time.Now().Add(5 * time.Minute) originatingMeta.DataEncoding = "foo" - originatingMeta.TotalObjects = numMsgs + originatingMeta.TotalObjects = int32(numMsgs) // calc expected records dataReader, err := NewDataReader(backend.NewContextReaderWithAllReader(bytes.NewReader(buffer.Bytes())), backend.EncNone) @@ -253,7 +253,7 @@ func streamingBlock(t *testing.T, cfg *common.BlockConfig, w backend.Writer) (*S dataReader, NewObjectReaderWriter()) - block, err := NewStreamingBlock(cfg, originatingMeta.BlockID, originatingMeta.TenantID, []*backend.BlockMeta{originatingMeta}, originatingMeta.TotalObjects) + block, err := NewStreamingBlock(cfg, originatingMeta.BlockID.UUID, originatingMeta.TenantID, []*backend.BlockMeta{originatingMeta}, int(originatingMeta.TotalObjects)) require.NoError(t, err, "unexpected error completing block") expectedBloomShards := block.bloom.GetShardCount() @@ -286,7 +286,7 @@ func streamingBlock(t *testing.T, cfg *common.BlockConfig, w backend.Writer) (*S require.Equal(t, expectedBloomShards, int(block.BlockMeta().BloomShardCount)) // Verify block size was written - require.Greater(t, block.BlockMeta().Size, uint64(0)) + require.Greater(t, block.BlockMeta().Size_, uint64(0)) return block, ids, reqs } @@ -386,7 +386,7 @@ func benchmarkCompressBlock(b *testing.B, encoding backend.Encoding, indexDownsa Encoding: encoding, IndexPageSizeBytes: 10 * 1024 * 1024, BloomShardSizeBytes: 100000, - }, uuid.New(), meta.TenantID, []*backend.BlockMeta{meta}, meta.TotalObjects) + }, uuid.New(), meta.TenantID, []*backend.BlockMeta{meta}, int(meta.TotalObjects)) require.NoError(b, err, "unexpected error completing block") ctx := context.Background() diff --git a/tempodb/encoding/v2/wal_block.go b/tempodb/encoding/v2/wal_block.go index 06035daa98f..13b05c7e149 100644 --- a/tempodb/encoding/v2/wal_block.go +++ b/tempodb/encoding/v2/wal_block.go @@ -54,7 +54,7 @@ func createWALBlock(meta *backend.BlockMeta, filepath, dataEncoding string, inge } h := &walBlock{ - meta: backend.NewBlockMeta(meta.TenantID, meta.BlockID, meta.Version, meta.Encoding, dataEncoding), + meta: backend.NewBlockMeta(meta.TenantID, meta.BlockID.UUID, meta.Version, meta.Encoding, dataEncoding), filepath: filepath, ingestionSlack: ingestionSlack, encoder: enc, @@ -132,7 +132,7 @@ func openWALBlock(filename, path string, ingestionSlack, additionalStartSlack ti } b.appender = NewRecordAppender(records) - b.meta.TotalObjects = b.appender.Length() + b.meta.TotalObjects = int32(b.appender.Length()) b.meta.StartTime = time.Unix(int64(blockStart), 0) b.meta.EndTime = time.Unix(int64(blockEnd), 0) diff --git a/tempodb/encoding/vparquet2/block_findtracebyid.go b/tempodb/encoding/vparquet2/block_findtracebyid.go index 879b3d7803d..c11b7f8950f 100644 --- a/tempodb/encoding/vparquet2/block_findtracebyid.go +++ b/tempodb/encoding/vparquet2/block_findtracebyid.go @@ -45,7 +45,7 @@ func (b *backendBlock) checkBloom(ctx context.Context, id common.ID) (found bool nameBloom := common.BloomName(shardKey) span.SetAttributes(attribute.String("bloom", nameBloom)) - bloomBytes, err := b.r.Read(derivedCtx, nameBloom, b.meta.BlockID, b.meta.TenantID, &backend.CacheInfo{ + bloomBytes, err := b.r.Read(derivedCtx, nameBloom, b.meta.BlockID.UUID, b.meta.TenantID, &backend.CacheInfo{ Meta: b.meta, Role: cache.RoleBloom, }) @@ -75,7 +75,7 @@ func (b *backendBlock) checkIndex(ctx context.Context, id common.ID) (bool, int, )) defer span.End() - indexBytes, err := b.r.Read(derivedCtx, common.NameIndex, b.meta.BlockID, b.meta.TenantID, &backend.CacheInfo{ + indexBytes, err := b.r.Read(derivedCtx, common.NameIndex, b.meta.BlockID.UUID, b.meta.TenantID, &backend.CacheInfo{ Meta: b.meta, Role: cache.RoleTraceIDIdx, }) @@ -105,7 +105,7 @@ func (b *backendBlock) FindTraceByID(ctx context.Context, traceID common.ID, opt trace.WithAttributes( attribute.String("blockID", b.meta.BlockID.String()), attribute.String("tenantID", b.meta.TenantID), - attribute.Int64("blockSize", int64(b.meta.Size)), + attribute.Int64("blockSize", int64(b.meta.Size_)), )) defer span.End() diff --git a/tempodb/encoding/vparquet2/block_findtracebyid_test.go b/tempodb/encoding/vparquet2/block_findtracebyid_test.go index 237a6e26413..d3c09b7e447 100644 --- a/tempodb/encoding/vparquet2/block_findtracebyid_test.go +++ b/tempodb/encoding/vparquet2/block_findtracebyid_test.go @@ -75,7 +75,7 @@ func TestBackendBlockFindTraceByID(t *testing.T) { }) meta := backend.NewBlockMeta("fake", uuid.New(), VersionString, backend.EncNone, "") - meta.TotalObjects = len(traces) + meta.TotalObjects = int32(len(traces)) s := newStreamingBlock(ctx, cfg, meta, r, w, tempo_io.NewBufferedWriter) // Write test data, occasionally flushing (cutting new row group) diff --git a/tempodb/encoding/vparquet2/block_iterator.go b/tempodb/encoding/vparquet2/block_iterator.go index 51e54cbb2df..2f717a3c7b0 100644 --- a/tempodb/encoding/vparquet2/block_iterator.go +++ b/tempodb/encoding/vparquet2/block_iterator.go @@ -17,9 +17,9 @@ func (b *backendBlock) open(ctx context.Context) (*parquet.File, *parquet.Reader rr := NewBackendReaderAt(ctx, b.r, DataFileName, b.meta) // 128 MB memory buffering - br := tempo_io.NewBufferedReaderAt(rr, int64(b.meta.Size), 2*1024*1024, 64) + br := tempo_io.NewBufferedReaderAt(rr, int64(b.meta.Size_), 2*1024*1024, 64) - pf, err := parquet.OpenFile(br, int64(b.meta.Size), parquet.SkipBloomFilters(true), parquet.SkipPageIndex(true)) + pf, err := parquet.OpenFile(br, int64(b.meta.Size_), parquet.SkipBloomFilters(true), parquet.SkipPageIndex(true)) if err != nil { return nil, nil, err } diff --git a/tempodb/encoding/vparquet2/block_iterator_test.go b/tempodb/encoding/vparquet2/block_iterator_test.go index 276e020ea72..1463a0dfb17 100644 --- a/tempodb/encoding/vparquet2/block_iterator_test.go +++ b/tempodb/encoding/vparquet2/block_iterator_test.go @@ -32,7 +32,7 @@ func TestRawIteratorReadsAllRows(t *testing.T) { require.NoError(t, err) defer iter.Close() - actualCount := 0 + actualCount := int32(0) for { _, tr, err := iter.Next(context.Background()) if tr == nil { diff --git a/tempodb/encoding/vparquet2/block_search.go b/tempodb/encoding/vparquet2/block_search.go index 6a32c5d1ebd..4b3c95c953f 100644 --- a/tempodb/encoding/vparquet2/block_search.go +++ b/tempodb/encoding/vparquet2/block_search.go @@ -80,22 +80,22 @@ func (b *backendBlock) openForSearch(ctx context.Context, opts common.SearchOpti if opts.ReadBufferSize > 0 { // only use buffered reader at if the block is small, otherwise it's far more effective to use larger // buffers in the parquet sdk - if opts.ReadBufferCount*opts.ReadBufferSize > int(b.meta.Size) { - readerAt = tempo_io.NewBufferedReaderAt(readerAt, int64(b.meta.Size), opts.ReadBufferSize, opts.ReadBufferCount) + if opts.ReadBufferCount*opts.ReadBufferSize > int(b.meta.Size_) { + readerAt = tempo_io.NewBufferedReaderAt(readerAt, int64(b.meta.Size_), opts.ReadBufferSize, opts.ReadBufferCount) } else { o = append(o, parquet.ReadBufferSize(opts.ReadBufferSize)) } } // optimized reader - readerAt = newParquetOptimizedReaderAt(readerAt, int64(b.meta.Size), b.meta.FooterSize) + readerAt = newParquetOptimizedReaderAt(readerAt, int64(b.meta.Size_), b.meta.FooterSize) // cached reader readerAt = newCachedReaderAt(readerAt, backendReaderAt) _, span := tracer.Start(ctx, "parquet.OpenFile") defer span.End() - pf, err := parquet.OpenFile(readerAt, int64(b.meta.Size), o...) + pf, err := parquet.OpenFile(readerAt, int64(b.meta.Size_), o...) return pf, backendReaderAt, err } @@ -105,7 +105,7 @@ func (b *backendBlock) Search(ctx context.Context, req *tempopb.SearchRequest, o trace.WithAttributes( attribute.String("blockID", b.meta.BlockID.String()), attribute.String("tenantID", b.meta.TenantID), - attribute.Int64("blockSize", int64(b.meta.Size)), + attribute.Int64("blockSize", int64(b.meta.Size_)), )) defer span.End() diff --git a/tempodb/encoding/vparquet2/block_search_tags.go b/tempodb/encoding/vparquet2/block_search_tags.go index 132fb007f4c..8c8480f6f86 100644 --- a/tempodb/encoding/vparquet2/block_search_tags.go +++ b/tempodb/encoding/vparquet2/block_search_tags.go @@ -48,7 +48,7 @@ func (b *backendBlock) SearchTags(ctx context.Context, scope traceql.AttributeSc trace.WithAttributes( attribute.String("blockID", b.meta.BlockID.String()), attribute.String("tenantID", b.meta.TenantID), - attribute.Int64("blockSize", int64(b.meta.Size)), + attribute.Int64("blockSize", int64(b.meta.Size_)), )) defer span.End() @@ -201,7 +201,7 @@ func (b *backendBlock) SearchTagValuesV2(ctx context.Context, tag traceql.Attrib trace.WithAttributes( attribute.String("blockID", b.meta.BlockID.String()), attribute.String("tenantID", b.meta.TenantID), - attribute.Int64("blockSize", int64(b.meta.Size)), + attribute.Int64("blockSize", int64(b.meta.Size_)), )) defer span.End() diff --git a/tempodb/encoding/vparquet2/compactor.go b/tempodb/encoding/vparquet2/compactor.go index f21507a8945..35a345b80aa 100644 --- a/tempodb/encoding/vparquet2/compactor.go +++ b/tempodb/encoding/vparquet2/compactor.go @@ -11,11 +11,12 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" - "github.com/google/uuid" + google_uuid "github.com/google/uuid" tempoUtil "github.com/grafana/tempo/pkg/util" "github.com/parquet-go/parquet-go" tempo_io "github.com/grafana/tempo/pkg/io" + "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/encoding/common" ) @@ -30,8 +31,8 @@ type Compactor struct { func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, w backend.Writer, inputs []*backend.BlockMeta) (newCompactedBlocks []*backend.BlockMeta, err error) { var ( - compactionLevel uint8 - totalRecords int + compactionLevel uint32 + totalRecords int32 minBlockStart time.Time maxBlockEnd time.Time bookmarks = make([]*bookmark[parquet.Row], 0, len(inputs)) @@ -127,7 +128,7 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, var ( m = newMultiblockIterator(bookmarks, combine) - recordsPerBlock = (totalRecords / int(c.opts.OutputBlocks)) + recordsPerBlock = (totalRecords / int32(c.opts.OutputBlocks)) currentBlock *streamingBlock ) defer m.Close() @@ -150,14 +151,14 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, if currentBlock == nil { // Start with a copy and then customize newMeta := &backend.BlockMeta{ - BlockID: uuid.New(), + BlockID: uuid.UUID{UUID: google_uuid.New()}, TenantID: inputs[0].TenantID, - CompactionLevel: nextCompactionLevel, - TotalObjects: recordsPerBlock, // Just an estimate + CompactionLevel: uint32(nextCompactionLevel), + TotalObjects: int32(recordsPerBlock), // Just an estimate } currentBlock = newStreamingBlock(ctx, &c.opts.BlockConfig, newMeta, r, w, tempo_io.NewBufferedWriter) - currentBlock.meta.CompactionLevel = nextCompactionLevel + currentBlock.meta.CompactionLevel = uint32(nextCompactionLevel) newCompactedBlocks = append(newCompactedBlocks, currentBlock.meta) } @@ -190,7 +191,7 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, pool.Put(lowestObject) // ship block to backend if done - if currentBlock.meta.TotalObjects >= recordsPerBlock { + if currentBlock.meta.TotalObjects >= int32(recordsPerBlock) { currentBlockPtrCopy := currentBlock currentBlockPtrCopy.meta.StartTime = minBlockStart currentBlockPtrCopy.meta.EndTime = maxBlockEnd diff --git a/tempodb/encoding/vparquet2/compactor_test.go b/tempodb/encoding/vparquet2/compactor_test.go index 678ae8087e6..e3085c92688 100644 --- a/tempodb/encoding/vparquet2/compactor_test.go +++ b/tempodb/encoding/vparquet2/compactor_test.go @@ -8,12 +8,13 @@ import ( "testing" "github.com/go-kit/log" - "github.com/google/uuid" + google_uuid "github.com/google/uuid" tempoUtil "github.com/grafana/tempo/pkg/util" "github.com/parquet-go/parquet-go" tempo_io "github.com/grafana/tempo/pkg/io" "github.com/grafana/tempo/pkg/util/test" + "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/backend/local" "github.com/grafana/tempo/tempodb/encoding/common" @@ -113,8 +114,8 @@ func BenchmarkCompactorDupes(b *testing.B) { func createTestBlock(t testing.TB, ctx context.Context, cfg *common.BlockConfig, r backend.Reader, w backend.Writer, traceCount, batchCount, spanCount int) *backend.BlockMeta { inMeta := &backend.BlockMeta{ TenantID: tenantID, - BlockID: uuid.New(), - TotalObjects: traceCount, + BlockID: uuid.UUID{UUID: google_uuid.New()}, + TotalObjects: int32(traceCount), } sb := newStreamingBlock(ctx, cfg, inMeta, r, w, tempo_io.NewBufferedWriter) diff --git a/tempodb/encoding/vparquet2/copy.go b/tempodb/encoding/vparquet2/copy.go index c3ee1b304c2..01342d73fb9 100644 --- a/tempodb/encoding/vparquet2/copy.go +++ b/tempodb/encoding/vparquet2/copy.go @@ -13,25 +13,25 @@ import ( func CopyBlock(ctx context.Context, fromMeta, toMeta *backend.BlockMeta, from backend.Reader, to backend.Writer) error { // Copy streams, efficient but can't cache. copyStream := func(name string) error { - reader, size, err := from.StreamReader(ctx, name, fromMeta.BlockID, fromMeta.TenantID) + reader, size, err := from.StreamReader(ctx, name, fromMeta.BlockID.UUID, fromMeta.TenantID) if err != nil { return fmt.Errorf("error reading %s: %w", name, err) } defer reader.Close() - return to.StreamWriter(ctx, name, toMeta.BlockID, toMeta.TenantID, reader, size) + return to.StreamWriter(ctx, name, toMeta.BlockID.UUID, toMeta.TenantID, reader, size) } // Read entire object and attempt to cache cpy := func(name string, cacheInfo *backend.CacheInfo) error { cacheInfo.Meta = fromMeta - b, err := from.Read(ctx, name, fromMeta.BlockID, fromMeta.TenantID, cacheInfo) + b, err := from.Read(ctx, name, fromMeta.BlockID.UUID, fromMeta.TenantID, cacheInfo) if err != nil { return fmt.Errorf("error reading %s: %w", name, err) } cacheInfo.Meta = toMeta - return to.Write(ctx, name, toMeta.BlockID, toMeta.TenantID, b, cacheInfo) + return to.Write(ctx, name, toMeta.BlockID.UUID, toMeta.TenantID, b, cacheInfo) } // Data @@ -72,7 +72,7 @@ func writeBlockMeta(ctx context.Context, w backend.Writer, meta *backend.BlockMe } for i, bloom := range blooms { nameBloom := common.BloomName(i) - err := w.Write(ctx, nameBloom, meta.BlockID, meta.TenantID, bloom, cacheInfo) + err := w.Write(ctx, nameBloom, meta.BlockID.UUID, meta.TenantID, bloom, cacheInfo) if err != nil { return fmt.Errorf("unexpected error writing bloom-%d: %w", i, err) } @@ -83,7 +83,7 @@ func writeBlockMeta(ctx context.Context, w backend.Writer, meta *backend.BlockMe if err != nil { return err } - err = w.Write(ctx, common.NameIndex, meta.BlockID, meta.TenantID, i, &backend.CacheInfo{ + err = w.Write(ctx, common.NameIndex, meta.BlockID.UUID, meta.TenantID, i, &backend.CacheInfo{ Meta: meta, Role: cache.RoleTraceIDIdx, }) diff --git a/tempodb/encoding/vparquet2/create.go b/tempodb/encoding/vparquet2/create.go index 72f4087b6a5..c6002594ee2 100644 --- a/tempodb/encoding/vparquet2/create.go +++ b/tempodb/encoding/vparquet2/create.go @@ -107,7 +107,7 @@ type streamingBlock struct { } func newStreamingBlock(ctx context.Context, cfg *common.BlockConfig, meta *backend.BlockMeta, r backend.Reader, to backend.Writer, createBufferedWriter func(w io.Writer) tempo_io.BufferedWriteFlusher) *streamingBlock { - newMeta := backend.NewBlockMeta(meta.TenantID, meta.BlockID, VersionString, backend.EncNone, "") + newMeta := backend.NewBlockMeta(meta.TenantID, meta.BlockID.UUID, VersionString, backend.EncNone, "") newMeta.StartTime = meta.StartTime newMeta.EndTime = meta.EndTime @@ -115,7 +115,7 @@ func newStreamingBlock(ctx context.Context, cfg *common.BlockConfig, meta *backe // The real number of objects is tracked below. bloom := common.NewBloom(cfg.BloomFP, uint(cfg.BloomShardSizeBytes), uint(meta.TotalObjects)) - w := &backendWriter{ctx, to, DataFileName, meta.BlockID, meta.TenantID, nil} + w := &backendWriter{ctx, to, DataFileName, meta.BlockID.UUID, meta.TenantID, nil} bw := createBufferedWriter(w) pw := parquet.NewGenericWriter[*Trace](bw) @@ -180,7 +180,7 @@ func (b *streamingBlock) Flush() (int, error) { } n := b.bw.Len() - b.meta.Size += uint64(n) + b.meta.Size_ += uint64(n) b.meta.TotalRecords++ b.currentBufferedTraces = 0 b.currentBufferedBytes = 0 @@ -206,7 +206,7 @@ func (b *streamingBlock) Complete() (int, error) { // Now Flush and close out in-memory buffer n := b.bw.Len() - b.meta.Size += uint64(n) + b.meta.Size_ += uint64(n) err = b.bw.Flush() if err != nil { return 0, err @@ -224,7 +224,7 @@ func (b *streamingBlock) Complete() (int, error) { // Read the footer size out of the parquet footer buf := make([]byte, 8) - err = b.r.ReadRange(b.ctx, DataFileName, b.meta.BlockID, b.meta.TenantID, b.meta.Size-8, buf, nil) + err = b.r.ReadRange(b.ctx, DataFileName, b.meta.BlockID.UUID, b.meta.TenantID, b.meta.Size_-8, buf, nil) if err != nil { return 0, fmt.Errorf("error reading parquet file footer: %w", err) } @@ -233,7 +233,7 @@ func (b *streamingBlock) Complete() (int, error) { } b.meta.FooterSize = binary.LittleEndian.Uint32(buf[0:4]) - b.meta.BloomShardCount = uint16(b.bloom.GetShardCount()) + b.meta.BloomShardCount = uint32(b.bloom.GetShardCount()) return n, writeBlockMeta(b.ctx, b.to, b.meta, b.bloom, b.index) } diff --git a/tempodb/encoding/vparquet2/readers.go b/tempodb/encoding/vparquet2/readers.go index 39c56ffdffc..6afba79a672 100644 --- a/tempodb/encoding/vparquet2/readers.go +++ b/tempodb/encoding/vparquet2/readers.go @@ -36,7 +36,7 @@ func NewBackendReaderAt(ctx context.Context, r backend.Reader, name string, meta func (b *BackendReaderAt) ReadAt(p []byte, off int64) (int, error) { b.bytesRead.Add(uint64(len(p))) - err := b.r.ReadRange(b.ctx, b.name, b.meta.BlockID, b.meta.TenantID, uint64(off), p, nil) + err := b.r.ReadRange(b.ctx, b.name, b.meta.BlockID.UUID, b.meta.TenantID, uint64(off), p, nil) if err != nil { return 0, err } @@ -44,7 +44,7 @@ func (b *BackendReaderAt) ReadAt(p []byte, off int64) (int, error) { } func (b *BackendReaderAt) ReadAtWithCache(p []byte, off int64, role cache.Role) (int, error) { - err := b.r.ReadRange(b.ctx, b.name, b.meta.BlockID, b.meta.TenantID, uint64(off), p, &backend.CacheInfo{ + err := b.r.ReadRange(b.ctx, b.name, b.meta.BlockID.UUID, b.meta.TenantID, uint64(off), p, &backend.CacheInfo{ Role: role, Meta: b.meta, }) diff --git a/tempodb/encoding/vparquet2/readers_test.go b/tempodb/encoding/vparquet2/readers_test.go index 1a9ded01705..138e140ae1b 100644 --- a/tempodb/encoding/vparquet2/readers_test.go +++ b/tempodb/encoding/vparquet2/readers_test.go @@ -49,7 +49,7 @@ func TestParquetGoSetsMetadataSections(t *testing.T) { br := NewBackendReaderAt(ctx, r, DataFileName, meta) dr := &dummyReader{r: br} - _, err = parquet.OpenFile(dr, int64(meta.Size)) + _, err = parquet.OpenFile(dr, int64(meta.Size_)) require.NoError(t, err) require.True(t, dr.footer) diff --git a/tempodb/encoding/vparquet3/block_findtracebyid.go b/tempodb/encoding/vparquet3/block_findtracebyid.go index 725d205fcce..84aaf497b10 100644 --- a/tempodb/encoding/vparquet3/block_findtracebyid.go +++ b/tempodb/encoding/vparquet3/block_findtracebyid.go @@ -45,7 +45,7 @@ func (b *backendBlock) checkBloom(ctx context.Context, id common.ID) (found bool nameBloom := common.BloomName(shardKey) span.SetAttributes(attribute.String("bloom", nameBloom)) - bloomBytes, err := b.r.Read(derivedCtx, nameBloom, b.meta.BlockID, b.meta.TenantID, &backend.CacheInfo{ + bloomBytes, err := b.r.Read(derivedCtx, nameBloom, b.meta.BlockID.UUID, b.meta.TenantID, &backend.CacheInfo{ Meta: b.meta, Role: cache.RoleBloom, }) @@ -75,7 +75,7 @@ func (b *backendBlock) checkIndex(ctx context.Context, id common.ID) (bool, int, )) defer span.End() - indexBytes, err := b.r.Read(derivedCtx, common.NameIndex, b.meta.BlockID, b.meta.TenantID, &backend.CacheInfo{ + indexBytes, err := b.r.Read(derivedCtx, common.NameIndex, b.meta.BlockID.UUID, b.meta.TenantID, &backend.CacheInfo{ Meta: b.meta, Role: cache.RoleTraceIDIdx, }) @@ -105,7 +105,7 @@ func (b *backendBlock) FindTraceByID(ctx context.Context, traceID common.ID, opt trace.WithAttributes( attribute.String("blockID", b.meta.BlockID.String()), attribute.String("tenantID", b.meta.TenantID), - attribute.Int64("blockSize", int64(b.meta.Size)), + attribute.Int64("blockSize", int64(b.meta.Size_)), )) defer span.End() diff --git a/tempodb/encoding/vparquet3/block_findtracebyid_test.go b/tempodb/encoding/vparquet3/block_findtracebyid_test.go index 4e83fdb1c59..ea8c40a265f 100644 --- a/tempodb/encoding/vparquet3/block_findtracebyid_test.go +++ b/tempodb/encoding/vparquet3/block_findtracebyid_test.go @@ -75,7 +75,7 @@ func TestBackendBlockFindTraceByID(t *testing.T) { }) meta := backend.NewBlockMeta("fake", uuid.New(), VersionString, backend.EncNone, "") - meta.TotalObjects = len(traces) + meta.TotalObjects = int32(len(traces)) s := newStreamingBlock(ctx, cfg, meta, r, w, tempo_io.NewBufferedWriter) // Write test data, occasionally flushing (cutting new row group) diff --git a/tempodb/encoding/vparquet3/block_iterator.go b/tempodb/encoding/vparquet3/block_iterator.go index 43891e7f8d8..2d6637b9c41 100644 --- a/tempodb/encoding/vparquet3/block_iterator.go +++ b/tempodb/encoding/vparquet3/block_iterator.go @@ -17,7 +17,7 @@ func (b *backendBlock) open(ctx context.Context) (*parquet.File, *parquet.Reader rr := NewBackendReaderAt(ctx, b.r, DataFileName, b.meta) // 128 MB memory buffering - br := tempo_io.NewBufferedReaderAt(rr, int64(b.meta.Size), 2*1024*1024, 64) + br := tempo_io.NewBufferedReaderAt(rr, int64(b.meta.Size_), 2*1024*1024, 64) o := []parquet.FileOption{ parquet.SkipBloomFilters(true), @@ -26,7 +26,7 @@ func (b *backendBlock) open(ctx context.Context) (*parquet.File, *parquet.Reader parquet.FileReadMode(parquet.ReadModeAsync), } - pf, err := parquet.OpenFile(br, int64(b.meta.Size), o...) + pf, err := parquet.OpenFile(br, int64(b.meta.Size_), o...) if err != nil { return nil, nil, err } diff --git a/tempodb/encoding/vparquet3/block_iterator_test.go b/tempodb/encoding/vparquet3/block_iterator_test.go index deef719bb09..390c9871cb7 100644 --- a/tempodb/encoding/vparquet3/block_iterator_test.go +++ b/tempodb/encoding/vparquet3/block_iterator_test.go @@ -32,7 +32,7 @@ func TestRawIteratorReadsAllRows(t *testing.T) { require.NoError(t, err) defer iter.Close() - actualCount := 0 + actualCount := int32(0) for { _, tr, err := iter.Next(context.Background()) if tr == nil { diff --git a/tempodb/encoding/vparquet3/block_search.go b/tempodb/encoding/vparquet3/block_search.go index bd71c1fd5f7..044ee5c3705 100644 --- a/tempodb/encoding/vparquet3/block_search.go +++ b/tempodb/encoding/vparquet3/block_search.go @@ -81,11 +81,11 @@ func (b *backendBlock) openForSearch(ctx context.Context, opts common.SearchOpti o = append(o, parquet.ReadBufferSize(readBufferSize)) // cached reader - cachedReaderAt := newCachedReaderAt(backendReaderAt, readBufferSize, int64(b.meta.Size), b.meta.FooterSize) // most reads to the backend are going to be readbuffersize so use it as our "page cache" size + cachedReaderAt := newCachedReaderAt(backendReaderAt, readBufferSize, int64(b.meta.Size_), b.meta.FooterSize) // most reads to the backend are going to be readbuffersize so use it as our "page cache" size _, span := tracer.Start(ctx, "parquet.OpenFile") defer span.End() - pf, err := parquet.OpenFile(cachedReaderAt, int64(b.meta.Size), o...) + pf, err := parquet.OpenFile(cachedReaderAt, int64(b.meta.Size_), o...) return pf, backendReaderAt, err } @@ -95,7 +95,7 @@ func (b *backendBlock) Search(ctx context.Context, req *tempopb.SearchRequest, o trace.WithAttributes( attribute.String("blockID", b.meta.BlockID.String()), attribute.String("tenantID", b.meta.TenantID), - attribute.Int64("blockSize", int64(b.meta.Size)), + attribute.Int64("blockSize", int64(b.meta.Size_)), )) defer span.End() diff --git a/tempodb/encoding/vparquet3/block_search_tags.go b/tempodb/encoding/vparquet3/block_search_tags.go index c0bcc3129c2..877aa07ebf2 100644 --- a/tempodb/encoding/vparquet3/block_search_tags.go +++ b/tempodb/encoding/vparquet3/block_search_tags.go @@ -49,7 +49,7 @@ func (b *backendBlock) SearchTags(ctx context.Context, scope traceql.AttributeSc trace.WithAttributes( attribute.String("blockID", b.meta.BlockID.String()), attribute.String("tenantID", b.meta.TenantID), - attribute.Int64("blockSize", int64(b.meta.Size)), + attribute.Int64("blockSize", int64(b.meta.Size_)), )) defer span.End() @@ -210,7 +210,7 @@ func (b *backendBlock) SearchTagValuesV2(ctx context.Context, tag traceql.Attrib trace.WithAttributes( attribute.String("blockID", b.meta.BlockID.String()), attribute.String("tenantID", b.meta.TenantID), - attribute.Int64("blockSize", int64(b.meta.Size)), + attribute.Int64("blockSize", int64(b.meta.Size_)), )) defer span.End() diff --git a/tempodb/encoding/vparquet3/compactor.go b/tempodb/encoding/vparquet3/compactor.go index c21c07fd447..ae0f9ac38d2 100644 --- a/tempodb/encoding/vparquet3/compactor.go +++ b/tempodb/encoding/vparquet3/compactor.go @@ -11,11 +11,12 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" - "github.com/google/uuid" + google_uuid "github.com/google/uuid" tempoUtil "github.com/grafana/tempo/pkg/util" "github.com/parquet-go/parquet-go" tempo_io "github.com/grafana/tempo/pkg/io" + "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/encoding/common" ) @@ -30,8 +31,8 @@ type Compactor struct { func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, w backend.Writer, inputs []*backend.BlockMeta) (newCompactedBlocks []*backend.BlockMeta, err error) { var ( - compactionLevel uint8 - totalRecords int + compactionLevel uint32 + totalRecords int32 minBlockStart time.Time maxBlockEnd time.Time bookmarks = make([]*bookmark[parquet.Row], 0, len(inputs)) @@ -43,7 +44,7 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, totalRecords += blockMeta.TotalObjects if blockMeta.CompactionLevel > compactionLevel { - compactionLevel = blockMeta.CompactionLevel + compactionLevel = uint32(blockMeta.CompactionLevel) } if blockMeta.StartTime.Before(minBlockStart) || minBlockStart.IsZero() { @@ -133,7 +134,7 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, var ( m = newMultiblockIterator(bookmarks, combine) - recordsPerBlock = (totalRecords / int(c.opts.OutputBlocks)) + recordsPerBlock = (totalRecords / int32(c.opts.OutputBlocks)) currentBlock *streamingBlock ) defer m.Close() @@ -156,16 +157,16 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, if currentBlock == nil { // Start with a copy and then customize newMeta := &backend.BlockMeta{ - BlockID: uuid.New(), + BlockID: uuid.UUID{UUID: google_uuid.New()}, TenantID: inputs[0].TenantID, - CompactionLevel: nextCompactionLevel, - TotalObjects: recordsPerBlock, // Just an estimate + CompactionLevel: uint32(nextCompactionLevel), + TotalObjects: int32(recordsPerBlock), // Just an estimate ReplicationFactor: inputs[0].ReplicationFactor, DedicatedColumns: inputs[0].DedicatedColumns, } currentBlock = newStreamingBlock(ctx, &c.opts.BlockConfig, newMeta, r, w, tempo_io.NewBufferedWriter) - currentBlock.meta.CompactionLevel = nextCompactionLevel + currentBlock.meta.CompactionLevel = uint32(nextCompactionLevel) newCompactedBlocks = append(newCompactedBlocks, currentBlock.meta) } @@ -198,7 +199,7 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, pool.Put(lowestObject) // ship block to backend if done - if currentBlock.meta.TotalObjects >= recordsPerBlock { + if currentBlock.meta.TotalObjects >= int32(recordsPerBlock) { currentBlockPtrCopy := currentBlock currentBlockPtrCopy.meta.StartTime = minBlockStart currentBlockPtrCopy.meta.EndTime = maxBlockEnd diff --git a/tempodb/encoding/vparquet3/compactor_test.go b/tempodb/encoding/vparquet3/compactor_test.go index 79a55e47094..082980d30fd 100644 --- a/tempodb/encoding/vparquet3/compactor_test.go +++ b/tempodb/encoding/vparquet3/compactor_test.go @@ -8,13 +8,14 @@ import ( "testing" "github.com/go-kit/log" - "github.com/google/uuid" + google_uuid "github.com/google/uuid" "github.com/parquet-go/parquet-go" "github.com/stretchr/testify/require" tempo_io "github.com/grafana/tempo/pkg/io" tempoUtil "github.com/grafana/tempo/pkg/util" "github.com/grafana/tempo/pkg/util/test" + "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/backend/local" "github.com/grafana/tempo/tempodb/encoding/common" @@ -113,9 +114,9 @@ func BenchmarkCompactorDupes(b *testing.B) { func createTestBlock(t testing.TB, ctx context.Context, cfg *common.BlockConfig, r backend.Reader, w backend.Writer, traceCount, batchCount, spanCount, replicationFactor int, dc backend.DedicatedColumns) *backend.BlockMeta { inMeta := &backend.BlockMeta{ TenantID: tenantID, - BlockID: uuid.New(), - TotalObjects: traceCount, - ReplicationFactor: uint8(replicationFactor), + BlockID: uuid.UUID{UUID: google_uuid.New()}, + TotalObjects: int32(traceCount), + ReplicationFactor: uint32(replicationFactor), DedicatedColumns: dc, } @@ -210,7 +211,7 @@ func TestCompact(t *testing.T) { newMeta, err := c.Compact(context.Background(), log.NewNopLogger(), r, w, inputs) require.NoError(t, err) require.Len(t, newMeta, 1) - require.Equal(t, 20, newMeta[0].TotalObjects) - require.Equal(t, uint8(1), newMeta[0].ReplicationFactor) + require.Equal(t, int32(20), newMeta[0].TotalObjects) + require.Equal(t, uint32(1), newMeta[0].ReplicationFactor) require.Equal(t, dedicatedColumns, newMeta[0].DedicatedColumns) } diff --git a/tempodb/encoding/vparquet3/copy.go b/tempodb/encoding/vparquet3/copy.go index 67213b3bde2..eb5762e1d22 100644 --- a/tempodb/encoding/vparquet3/copy.go +++ b/tempodb/encoding/vparquet3/copy.go @@ -13,25 +13,25 @@ import ( func CopyBlock(ctx context.Context, fromMeta, toMeta *backend.BlockMeta, from backend.Reader, to backend.Writer) error { // Copy streams, efficient but can't cache. copyStream := func(name string) error { - reader, size, err := from.StreamReader(ctx, name, fromMeta.BlockID, fromMeta.TenantID) + reader, size, err := from.StreamReader(ctx, name, fromMeta.BlockID.UUID, fromMeta.TenantID) if err != nil { return fmt.Errorf("error reading %s: %w", name, err) } defer reader.Close() - return to.StreamWriter(ctx, name, toMeta.BlockID, toMeta.TenantID, reader, size) + return to.StreamWriter(ctx, name, toMeta.BlockID.UUID, toMeta.TenantID, reader, size) } // Read entire object and attempt to cache cpy := func(name string, cacheInfo *backend.CacheInfo) error { cacheInfo.Meta = fromMeta - b, err := from.Read(ctx, name, fromMeta.BlockID, fromMeta.TenantID, cacheInfo) + b, err := from.Read(ctx, name, fromMeta.BlockID.UUID, fromMeta.TenantID, cacheInfo) if err != nil { return fmt.Errorf("error reading %s: %w", name, err) } cacheInfo.Meta = toMeta - return to.Write(ctx, name, toMeta.BlockID, toMeta.TenantID, b, cacheInfo) + return to.Write(ctx, name, toMeta.BlockID.UUID, toMeta.TenantID, b, cacheInfo) } // Data @@ -73,7 +73,7 @@ func writeBlockMeta(ctx context.Context, w backend.Writer, meta *backend.BlockMe } for i, bloom := range blooms { nameBloom := common.BloomName(i) - err := w.Write(ctx, nameBloom, meta.BlockID, meta.TenantID, bloom, cacheInfo) + err := w.Write(ctx, nameBloom, meta.BlockID.UUID, meta.TenantID, bloom, cacheInfo) if err != nil { return fmt.Errorf("unexpected error writing bloom-%d: %w", i, err) } @@ -84,7 +84,7 @@ func writeBlockMeta(ctx context.Context, w backend.Writer, meta *backend.BlockMe if err != nil { return err } - err = w.Write(ctx, common.NameIndex, meta.BlockID, meta.TenantID, i, &backend.CacheInfo{ + err = w.Write(ctx, common.NameIndex, meta.BlockID.UUID, meta.TenantID, i, &backend.CacheInfo{ Meta: meta, Role: cache.RoleTraceIDIdx, }) diff --git a/tempodb/encoding/vparquet3/create.go b/tempodb/encoding/vparquet3/create.go index 7339dfee59f..03195e85511 100644 --- a/tempodb/encoding/vparquet3/create.go +++ b/tempodb/encoding/vparquet3/create.go @@ -107,7 +107,7 @@ type streamingBlock struct { } func newStreamingBlock(ctx context.Context, cfg *common.BlockConfig, meta *backend.BlockMeta, r backend.Reader, to backend.Writer, createBufferedWriter func(w io.Writer) tempo_io.BufferedWriteFlusher) *streamingBlock { - newMeta := backend.NewBlockMetaWithDedicatedColumns(meta.TenantID, meta.BlockID, VersionString, backend.EncNone, "", meta.DedicatedColumns) + newMeta := backend.NewBlockMetaWithDedicatedColumns(meta.TenantID, meta.BlockID.UUID, VersionString, backend.EncNone, "", meta.DedicatedColumns) newMeta.StartTime = meta.StartTime newMeta.EndTime = meta.EndTime newMeta.ReplicationFactor = meta.ReplicationFactor @@ -116,7 +116,7 @@ func newStreamingBlock(ctx context.Context, cfg *common.BlockConfig, meta *backe // The real number of objects is tracked below. bloom := common.NewBloom(cfg.BloomFP, uint(cfg.BloomShardSizeBytes), uint(meta.TotalObjects)) - w := &backendWriter{ctx, to, DataFileName, meta.BlockID, meta.TenantID, nil} + w := &backendWriter{ctx, to, DataFileName, meta.BlockID.UUID, meta.TenantID, nil} bw := createBufferedWriter(w) pw := parquet.NewGenericWriter[*Trace](bw) @@ -181,7 +181,7 @@ func (b *streamingBlock) Flush() (int, error) { } n := b.bw.Len() - b.meta.Size += uint64(n) + b.meta.Size_ += uint64(n) b.meta.TotalRecords++ b.currentBufferedTraces = 0 b.currentBufferedBytes = 0 @@ -207,7 +207,7 @@ func (b *streamingBlock) Complete() (int, error) { // Now Flush and close out in-memory buffer n := b.bw.Len() - b.meta.Size += uint64(n) + b.meta.Size_ += uint64(n) err = b.bw.Flush() if err != nil { return 0, err @@ -225,7 +225,7 @@ func (b *streamingBlock) Complete() (int, error) { // Read the footer size out of the parquet footer buf := make([]byte, 8) - err = b.r.ReadRange(b.ctx, DataFileName, b.meta.BlockID, b.meta.TenantID, b.meta.Size-8, buf, nil) + err = b.r.ReadRange(b.ctx, DataFileName, b.meta.BlockID.UUID, b.meta.TenantID, b.meta.Size_-8, buf, nil) if err != nil { return 0, fmt.Errorf("error reading parquet file footer: %w", err) } @@ -234,7 +234,7 @@ func (b *streamingBlock) Complete() (int, error) { } b.meta.FooterSize = binary.LittleEndian.Uint32(buf[0:4]) - b.meta.BloomShardCount = uint16(b.bloom.GetShardCount()) + b.meta.BloomShardCount = uint32(b.bloom.GetShardCount()) return n, writeBlockMeta(b.ctx, b.to, b.meta, b.bloom, b.index) } diff --git a/tempodb/encoding/vparquet3/readers.go b/tempodb/encoding/vparquet3/readers.go index e6fd761db1e..1b8cc8f23e7 100644 --- a/tempodb/encoding/vparquet3/readers.go +++ b/tempodb/encoding/vparquet3/readers.go @@ -37,7 +37,7 @@ func (b *BackendReaderAt) ReadAt(p []byte, off int64) (int, error) { } func (b *BackendReaderAt) ReadAtWithCache(p []byte, off int64, role cache.Role) (int, error) { - err := b.r.ReadRange(b.ctx, b.name, b.meta.BlockID, b.meta.TenantID, uint64(off), p, &backend.CacheInfo{ + err := b.r.ReadRange(b.ctx, b.name, b.meta.BlockID.UUID, b.meta.TenantID, uint64(off), p, &backend.CacheInfo{ Role: role, Meta: b.meta, }) diff --git a/tempodb/encoding/vparquet3/readers_test.go b/tempodb/encoding/vparquet3/readers_test.go index c6e3de2789b..88c808e59d9 100644 --- a/tempodb/encoding/vparquet3/readers_test.go +++ b/tempodb/encoding/vparquet3/readers_test.go @@ -50,7 +50,7 @@ func TestParquetGoSetsMetadataSections(t *testing.T) { br := NewBackendReaderAt(ctx, r, DataFileName, meta) dr := &dummyReader{r: br} - _, err = parquet.OpenFile(dr, int64(meta.Size)) + _, err = parquet.OpenFile(dr, int64(meta.Size_)) require.NoError(t, err) require.True(t, dr.footer) diff --git a/tempodb/encoding/vparquet4/block_findtracebyid.go b/tempodb/encoding/vparquet4/block_findtracebyid.go index 74ab2e8ba9b..c782bbf8c0e 100644 --- a/tempodb/encoding/vparquet4/block_findtracebyid.go +++ b/tempodb/encoding/vparquet4/block_findtracebyid.go @@ -45,7 +45,7 @@ func (b *backendBlock) checkBloom(ctx context.Context, id common.ID) (found bool nameBloom := common.BloomName(shardKey) span.SetAttributes(attribute.String("bloom", nameBloom)) - bloomBytes, err := b.r.Read(derivedCtx, nameBloom, b.meta.BlockID, b.meta.TenantID, &backend.CacheInfo{ + bloomBytes, err := b.r.Read(derivedCtx, nameBloom, b.meta.BlockID.UUID, b.meta.TenantID, &backend.CacheInfo{ Meta: b.meta, Role: cache.RoleBloom, }) @@ -75,7 +75,7 @@ func (b *backendBlock) checkIndex(ctx context.Context, id common.ID) (bool, int, )) defer span.End() - indexBytes, err := b.r.Read(derivedCtx, common.NameIndex, b.meta.BlockID, b.meta.TenantID, &backend.CacheInfo{ + indexBytes, err := b.r.Read(derivedCtx, common.NameIndex, b.meta.BlockID.UUID, b.meta.TenantID, &backend.CacheInfo{ Meta: b.meta, Role: cache.RoleTraceIDIdx, }) @@ -105,7 +105,7 @@ func (b *backendBlock) FindTraceByID(ctx context.Context, traceID common.ID, opt trace.WithAttributes( attribute.String("blockID", b.meta.BlockID.String()), attribute.String("tenantID", b.meta.TenantID), - attribute.Int64("blockSize", int64(b.meta.Size)), + attribute.Int64("blockSize", int64(b.meta.Size_)), )) defer span.End() diff --git a/tempodb/encoding/vparquet4/block_findtracebyid_test.go b/tempodb/encoding/vparquet4/block_findtracebyid_test.go index 5f5609fb64e..5eceeb41d04 100644 --- a/tempodb/encoding/vparquet4/block_findtracebyid_test.go +++ b/tempodb/encoding/vparquet4/block_findtracebyid_test.go @@ -75,7 +75,7 @@ func TestBackendBlockFindTraceByID(t *testing.T) { }) meta := backend.NewBlockMeta("fake", uuid.New(), VersionString, backend.EncNone, "") - meta.TotalObjects = len(traces) + meta.TotalObjects = int32(len(traces)) s := newStreamingBlock(ctx, cfg, meta, r, w, tempo_io.NewBufferedWriter) // Write test data, occasionally flushing (cutting new row group) diff --git a/tempodb/encoding/vparquet4/block_iterator.go b/tempodb/encoding/vparquet4/block_iterator.go index 064f33429cf..201648513c0 100644 --- a/tempodb/encoding/vparquet4/block_iterator.go +++ b/tempodb/encoding/vparquet4/block_iterator.go @@ -17,7 +17,7 @@ func (b *backendBlock) open(ctx context.Context) (*parquet.File, *parquet.Reader rr := NewBackendReaderAt(ctx, b.r, DataFileName, b.meta) // 128 MB memory buffering - br := tempo_io.NewBufferedReaderAt(rr, int64(b.meta.Size), 2*1024*1024, 64) + br := tempo_io.NewBufferedReaderAt(rr, int64(b.meta.Size_), 2*1024*1024, 64) o := []parquet.FileOption{ parquet.SkipBloomFilters(true), @@ -26,7 +26,7 @@ func (b *backendBlock) open(ctx context.Context) (*parquet.File, *parquet.Reader parquet.FileReadMode(parquet.ReadModeAsync), } - pf, err := parquet.OpenFile(br, int64(b.meta.Size), o...) + pf, err := parquet.OpenFile(br, int64(b.meta.Size_), o...) if err != nil { return nil, nil, err } diff --git a/tempodb/encoding/vparquet4/block_iterator_test.go b/tempodb/encoding/vparquet4/block_iterator_test.go index d8f952b7f30..2a501310919 100644 --- a/tempodb/encoding/vparquet4/block_iterator_test.go +++ b/tempodb/encoding/vparquet4/block_iterator_test.go @@ -32,7 +32,7 @@ func TestRawIteratorReadsAllRows(t *testing.T) { require.NoError(t, err) defer iter.Close() - actualCount := 0 + actualCount := int32(0) for { _, tr, err := iter.Next(context.Background()) if tr == nil { diff --git a/tempodb/encoding/vparquet4/block_search.go b/tempodb/encoding/vparquet4/block_search.go index 1d1432f5291..fe9a8c64555 100644 --- a/tempodb/encoding/vparquet4/block_search.go +++ b/tempodb/encoding/vparquet4/block_search.go @@ -81,11 +81,11 @@ func (b *backendBlock) openForSearch(ctx context.Context, opts common.SearchOpti o = append(o, parquet.ReadBufferSize(readBufferSize)) // cached reader - cachedReaderAt := newCachedReaderAt(backendReaderAt, readBufferSize, int64(b.meta.Size), b.meta.FooterSize) // most reads to the backend are going to be readbuffersize so use it as our "page cache" size + cachedReaderAt := newCachedReaderAt(backendReaderAt, readBufferSize, int64(b.meta.Size_), b.meta.FooterSize) // most reads to the backend are going to be readbuffersize so use it as our "page cache" size _, span := tracer.Start(ctx, "parquet.OpenFile") defer span.End() - pf, err := parquet.OpenFile(cachedReaderAt, int64(b.meta.Size), o...) + pf, err := parquet.OpenFile(cachedReaderAt, int64(b.meta.Size_), o...) return pf, backendReaderAt, err } @@ -95,7 +95,7 @@ func (b *backendBlock) Search(ctx context.Context, req *tempopb.SearchRequest, o trace.WithAttributes( attribute.String("blockID", b.meta.BlockID.String()), attribute.String("tenantID", b.meta.TenantID), - attribute.Int64("blockSize", int64(b.meta.Size)), + attribute.Int64("blockSize", int64(b.meta.Size_)), )) defer span.End() diff --git a/tempodb/encoding/vparquet4/block_search_tags.go b/tempodb/encoding/vparquet4/block_search_tags.go index d45cf38876f..7913d01406c 100644 --- a/tempodb/encoding/vparquet4/block_search_tags.go +++ b/tempodb/encoding/vparquet4/block_search_tags.go @@ -49,7 +49,7 @@ func (b *backendBlock) SearchTags(ctx context.Context, scope traceql.AttributeSc trace.WithAttributes( attribute.String("blockID", b.meta.BlockID.String()), attribute.String("tenantID", b.meta.TenantID), - attribute.Int64("blockSize", int64(b.meta.Size)), + attribute.Int64("blockSize", int64(b.meta.Size_)), )) defer span.End() @@ -231,7 +231,7 @@ func (b *backendBlock) SearchTagValuesV2(ctx context.Context, tag traceql.Attrib trace.WithAttributes( attribute.String("blockID", b.meta.BlockID.String()), attribute.String("tenantID", b.meta.TenantID), - attribute.Int64("blockSize", int64(b.meta.Size)), + attribute.Int64("blockSize", int64(b.meta.Size_)), )) defer span.End() diff --git a/tempodb/encoding/vparquet4/compactor.go b/tempodb/encoding/vparquet4/compactor.go index 89409bc120e..58c5139aba6 100644 --- a/tempodb/encoding/vparquet4/compactor.go +++ b/tempodb/encoding/vparquet4/compactor.go @@ -11,11 +11,12 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" - "github.com/google/uuid" + google_uuid "github.com/google/uuid" tempoUtil "github.com/grafana/tempo/pkg/util" "github.com/parquet-go/parquet-go" tempo_io "github.com/grafana/tempo/pkg/io" + "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/encoding/common" ) @@ -30,8 +31,8 @@ type Compactor struct { func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, w backend.Writer, inputs []*backend.BlockMeta) (newCompactedBlocks []*backend.BlockMeta, err error) { var ( - compactionLevel uint8 - totalRecords int + compactionLevel uint32 + totalRecords int32 minBlockStart time.Time maxBlockEnd time.Time bookmarks = make([]*bookmark[parquet.Row], 0, len(inputs)) @@ -133,7 +134,7 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, var ( m = newMultiblockIterator(bookmarks, combine) - recordsPerBlock = (totalRecords / int(c.opts.OutputBlocks)) + recordsPerBlock = (totalRecords / int32(c.opts.OutputBlocks)) currentBlock *streamingBlock ) defer m.Close() @@ -156,7 +157,7 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, if currentBlock == nil { // Start with a copy and then customize newMeta := &backend.BlockMeta{ - BlockID: uuid.New(), + BlockID: uuid.UUID{UUID: google_uuid.New()}, TenantID: inputs[0].TenantID, CompactionLevel: nextCompactionLevel, TotalObjects: recordsPerBlock, // Just an estimate diff --git a/tempodb/encoding/vparquet4/compactor_test.go b/tempodb/encoding/vparquet4/compactor_test.go index 5a72540ebee..b5bf0f6b02a 100644 --- a/tempodb/encoding/vparquet4/compactor_test.go +++ b/tempodb/encoding/vparquet4/compactor_test.go @@ -8,13 +8,14 @@ import ( "testing" "github.com/go-kit/log" - "github.com/google/uuid" + google_uuid "github.com/google/uuid" "github.com/parquet-go/parquet-go" "github.com/stretchr/testify/require" tempo_io "github.com/grafana/tempo/pkg/io" tempoUtil "github.com/grafana/tempo/pkg/util" "github.com/grafana/tempo/pkg/util/test" + "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/backend/local" "github.com/grafana/tempo/tempodb/encoding/common" @@ -113,9 +114,9 @@ func BenchmarkCompactorDupes(b *testing.B) { func createTestBlock(t testing.TB, ctx context.Context, cfg *common.BlockConfig, r backend.Reader, w backend.Writer, traceCount, batchCount, spanCount, replicationFactor int, dc backend.DedicatedColumns) *backend.BlockMeta { inMeta := &backend.BlockMeta{ TenantID: tenantID, - BlockID: uuid.New(), - TotalObjects: traceCount, - ReplicationFactor: uint8(replicationFactor), + BlockID: uuid.UUID{UUID: google_uuid.New()}, + TotalObjects: int32(traceCount), + ReplicationFactor: uint32(replicationFactor), DedicatedColumns: dc, } @@ -210,7 +211,7 @@ func TestCompact(t *testing.T) { newMeta, err := c.Compact(context.Background(), log.NewNopLogger(), r, w, inputs) require.NoError(t, err) require.Len(t, newMeta, 1) - require.Equal(t, 20, newMeta[0].TotalObjects) - require.Equal(t, uint8(1), newMeta[0].ReplicationFactor) + require.Equal(t, int32(20), newMeta[0].TotalObjects) + require.Equal(t, uint32(1), newMeta[0].ReplicationFactor) require.Equal(t, dedicatedColumns, newMeta[0].DedicatedColumns) } diff --git a/tempodb/encoding/vparquet4/copy.go b/tempodb/encoding/vparquet4/copy.go index a4575193e95..37927fc2869 100644 --- a/tempodb/encoding/vparquet4/copy.go +++ b/tempodb/encoding/vparquet4/copy.go @@ -13,25 +13,25 @@ import ( func CopyBlock(ctx context.Context, fromMeta, toMeta *backend.BlockMeta, from backend.Reader, to backend.Writer) error { // Copy streams, efficient but can't cache. copyStream := func(name string) error { - reader, size, err := from.StreamReader(ctx, name, fromMeta.BlockID, fromMeta.TenantID) + reader, size, err := from.StreamReader(ctx, name, fromMeta.BlockID.UUID, fromMeta.TenantID) if err != nil { return fmt.Errorf("error reading %s: %w", name, err) } defer reader.Close() - return to.StreamWriter(ctx, name, toMeta.BlockID, toMeta.TenantID, reader, size) + return to.StreamWriter(ctx, name, toMeta.BlockID.UUID, toMeta.TenantID, reader, size) } // Read entire object and attempt to cache cpy := func(name string, cacheInfo *backend.CacheInfo) error { cacheInfo.Meta = fromMeta - b, err := from.Read(ctx, name, fromMeta.BlockID, fromMeta.TenantID, cacheInfo) + b, err := from.Read(ctx, name, fromMeta.BlockID.UUID, fromMeta.TenantID, cacheInfo) if err != nil { return fmt.Errorf("error reading %s: %w", name, err) } cacheInfo.Meta = toMeta - return to.Write(ctx, name, toMeta.BlockID, toMeta.TenantID, b, cacheInfo) + return to.Write(ctx, name, toMeta.BlockID.UUID, toMeta.TenantID, b, cacheInfo) } // Data @@ -73,7 +73,7 @@ func writeBlockMeta(ctx context.Context, w backend.Writer, meta *backend.BlockMe } for i, bloom := range blooms { nameBloom := common.BloomName(i) - err := w.Write(ctx, nameBloom, meta.BlockID, meta.TenantID, bloom, cacheInfo) + err := w.Write(ctx, nameBloom, meta.BlockID.UUID, meta.TenantID, bloom, cacheInfo) if err != nil { return fmt.Errorf("unexpected error writing bloom-%d: %w", i, err) } @@ -84,7 +84,7 @@ func writeBlockMeta(ctx context.Context, w backend.Writer, meta *backend.BlockMe if err != nil { return err } - err = w.Write(ctx, common.NameIndex, meta.BlockID, meta.TenantID, i, &backend.CacheInfo{ + err = w.Write(ctx, common.NameIndex, meta.BlockID.UUID, meta.TenantID, i, &backend.CacheInfo{ Meta: meta, Role: cache.RoleTraceIDIdx, }) diff --git a/tempodb/encoding/vparquet4/create.go b/tempodb/encoding/vparquet4/create.go index 4f6bd75c853..e698e85a6e9 100644 --- a/tempodb/encoding/vparquet4/create.go +++ b/tempodb/encoding/vparquet4/create.go @@ -107,7 +107,7 @@ type streamingBlock struct { } func newStreamingBlock(ctx context.Context, cfg *common.BlockConfig, meta *backend.BlockMeta, r backend.Reader, to backend.Writer, createBufferedWriter func(w io.Writer) tempo_io.BufferedWriteFlusher) *streamingBlock { - newMeta := backend.NewBlockMetaWithDedicatedColumns(meta.TenantID, meta.BlockID, VersionString, backend.EncNone, "", meta.DedicatedColumns) + newMeta := backend.NewBlockMetaWithDedicatedColumns(meta.TenantID, meta.BlockID.UUID, VersionString, backend.EncNone, "", meta.DedicatedColumns) newMeta.StartTime = meta.StartTime newMeta.EndTime = meta.EndTime newMeta.ReplicationFactor = meta.ReplicationFactor @@ -116,7 +116,7 @@ func newStreamingBlock(ctx context.Context, cfg *common.BlockConfig, meta *backe // The real number of objects is tracked below. bloom := common.NewBloom(cfg.BloomFP, uint(cfg.BloomShardSizeBytes), uint(meta.TotalObjects)) - w := &backendWriter{ctx, to, DataFileName, meta.BlockID, meta.TenantID, nil} + w := &backendWriter{ctx, to, DataFileName, meta.BlockID.UUID, meta.TenantID, nil} bw := createBufferedWriter(w) pw := parquet.NewGenericWriter[*Trace](bw) @@ -181,7 +181,7 @@ func (b *streamingBlock) Flush() (int, error) { } n := b.bw.Len() - b.meta.Size += uint64(n) + b.meta.Size_ += uint64(n) b.meta.TotalRecords++ b.currentBufferedTraces = 0 b.currentBufferedBytes = 0 @@ -207,7 +207,7 @@ func (b *streamingBlock) Complete() (int, error) { // Now Flush and close out in-memory buffer n := b.bw.Len() - b.meta.Size += uint64(n) + b.meta.Size_ += uint64(n) err = b.bw.Flush() if err != nil { return 0, err @@ -225,7 +225,7 @@ func (b *streamingBlock) Complete() (int, error) { // Read the footer size out of the parquet footer buf := make([]byte, 8) - err = b.r.ReadRange(b.ctx, DataFileName, b.meta.BlockID, b.meta.TenantID, b.meta.Size-8, buf, nil) + err = b.r.ReadRange(b.ctx, DataFileName, b.meta.BlockID.UUID, b.meta.TenantID, b.meta.Size_-8, buf, nil) if err != nil { return 0, fmt.Errorf("error reading parquet file footer: %w", err) } @@ -234,7 +234,7 @@ func (b *streamingBlock) Complete() (int, error) { } b.meta.FooterSize = binary.LittleEndian.Uint32(buf[0:4]) - b.meta.BloomShardCount = uint16(b.bloom.GetShardCount()) + b.meta.BloomShardCount = uint32(b.bloom.GetShardCount()) return n, writeBlockMeta(b.ctx, b.to, b.meta, b.bloom, b.index) } diff --git a/tempodb/encoding/vparquet4/readers.go b/tempodb/encoding/vparquet4/readers.go index 928d2f923d3..9a170786ed2 100644 --- a/tempodb/encoding/vparquet4/readers.go +++ b/tempodb/encoding/vparquet4/readers.go @@ -37,7 +37,7 @@ func (b *BackendReaderAt) ReadAt(p []byte, off int64) (int, error) { } func (b *BackendReaderAt) ReadAtWithCache(p []byte, off int64, role cache.Role) (int, error) { - err := b.r.ReadRange(b.ctx, b.name, b.meta.BlockID, b.meta.TenantID, uint64(off), p, &backend.CacheInfo{ + err := b.r.ReadRange(b.ctx, b.name, b.meta.BlockID.UUID, b.meta.TenantID, uint64(off), p, &backend.CacheInfo{ Role: role, Meta: b.meta, }) diff --git a/tempodb/encoding/vparquet4/readers_test.go b/tempodb/encoding/vparquet4/readers_test.go index 5a25ed5e269..6bcf2ff8546 100644 --- a/tempodb/encoding/vparquet4/readers_test.go +++ b/tempodb/encoding/vparquet4/readers_test.go @@ -50,7 +50,7 @@ func TestParquetGoSetsMetadataSections(t *testing.T) { br := NewBackendReaderAt(ctx, r, DataFileName, meta) dr := &dummyReader{r: br} - _, err = parquet.OpenFile(dr, int64(meta.Size)) + _, err = parquet.OpenFile(dr, int64(meta.Size_)) require.NoError(t, err) require.True(t, dr.footer) diff --git a/tempodb/retention.go b/tempodb/retention.go index 96334210ed7..c56ef7c897b 100644 --- a/tempodb/retention.go +++ b/tempodb/retention.go @@ -66,7 +66,7 @@ func (rw *readerWriter) retainTenant(ctx context.Context, tenantID string) { default: if b.EndTime.Before(cutoff) && rw.compactorSharder.Owns(b.BlockID.String()) { level.Info(rw.logger).Log("msg", "marking block for deletion", "blockID", b.BlockID, "tenantID", tenantID) - err := rw.c.MarkBlockCompacted(b.BlockID, tenantID) + err := rw.c.MarkBlockCompacted(b.BlockID.UUID, tenantID) if err != nil { level.Error(rw.logger).Log("msg", "failed to mark block compacted during retention", "blockID", b.BlockID, "tenantID", tenantID, "err", err) metricRetentionErrors.Inc() @@ -95,7 +95,7 @@ func (rw *readerWriter) retainTenant(ctx context.Context, tenantID string) { level.Debug(rw.logger).Log("owns", rw.compactorSharder.Owns(b.BlockID.String()), "blockID", b.BlockID, "tenantID", tenantID) if b.CompactedTime.Before(cutoff) && rw.compactorSharder.Owns(b.BlockID.String()) { level.Info(rw.logger).Log("msg", "deleting block", "blockID", b.BlockID, "tenantID", tenantID) - err := rw.c.ClearBlock(b.BlockID, tenantID) + err := rw.c.ClearBlock(b.BlockID.UUID, tenantID) if err != nil { level.Error(rw.logger).Log("msg", "failed to clear compacted block during retention", "blockID", b.BlockID, "tenantID", tenantID, "err", err) metricRetentionErrors.Inc() diff --git a/tempodb/retention_test.go b/tempodb/retention_test.go index adbe4f79d1c..32fb252e048 100644 --- a/tempodb/retention_test.go +++ b/tempodb/retention_test.go @@ -7,11 +7,12 @@ import ( "time" "github.com/go-kit/log" - "github.com/google/uuid" + google_uuid "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/grafana/tempo/pkg/model" + "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/backend/local" "github.com/grafana/tempo/tempodb/encoding" @@ -53,7 +54,7 @@ func TestRetention(t *testing.T) { r.EnablePolling(ctx, &mockJobSharder{}) - blockID := uuid.New() + blockID := uuid.UUID{UUID: google_uuid.New()} wal := w.WAL() assert.NoError(t, err) @@ -68,15 +69,15 @@ func TestRetention(t *testing.T) { rw := r.(*readerWriter) // poll - checkBlocklists(t, blockID, 1, 0, rw) + checkBlocklists(t, blockID.UUID, 1, 0, rw) // retention should mark it compacted r.(*readerWriter).doRetention(ctx) - checkBlocklists(t, blockID, 0, 1, rw) + checkBlocklists(t, blockID.UUID, 0, 1, rw) // retention again should clear it r.(*readerWriter).doRetention(ctx) - checkBlocklists(t, blockID, 0, 0, rw) + checkBlocklists(t, blockID.UUID, 0, 0, rw) } func TestRetentionUpdatesBlocklistImmediately(t *testing.T) { @@ -120,7 +121,7 @@ func TestRetentionUpdatesBlocklistImmediately(t *testing.T) { wal := w.WAL() assert.NoError(t, err) - blockID := uuid.New() + blockID := uuid.UUID{UUID: google_uuid.New()} meta := &backend.BlockMeta{BlockID: blockID, TenantID: testTenantID} head, err := wal.NewBlock(meta, model.CurrentEncoding) diff --git a/tempodb/tempodb.go b/tempodb/tempodb.go index 0e523ec3e7c..c5ef7a427a9 100644 --- a/tempodb/tempodb.go +++ b/tempodb/tempodb.go @@ -610,7 +610,7 @@ func includeBlock(b *backend.BlockMeta, _ common.ID, blockStart, blockEnd []byte return false } - return b.ReplicationFactor == uint8(replicationFactor) + return b.ReplicationFactor == uint32(replicationFactor) } // if block is compacted within lookback period, and is within shard ranges, include it in search diff --git a/tempodb/tempodb_search_test.go b/tempodb/tempodb_search_test.go index a6eb0778db5..6c4ccf98024 100644 --- a/tempodb/tempodb_search_test.go +++ b/tempodb/tempodb_search_test.go @@ -13,7 +13,7 @@ import ( "time" "github.com/go-kit/log" - "github.com/google/uuid" + google_uuid "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -29,6 +29,7 @@ import ( "github.com/grafana/tempo/pkg/util" "github.com/grafana/tempo/pkg/util/math" "github.com/grafana/tempo/pkg/util/test" + "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/backend/local" "github.com/grafana/tempo/tempodb/encoding" @@ -1620,7 +1621,7 @@ func runCompleteBlockSearchTest(t *testing.T, blockVersion string, runners ...ru // Write to wal wal := w.WAL() - meta := &backend.BlockMeta{BlockID: uuid.New(), TenantID: testTenantID, DedicatedColumns: dc} + meta := &backend.BlockMeta{BlockID: uuid.UUID{UUID: google_uuid.New()}, TenantID: testTenantID, DedicatedColumns: dc} head, err := wal.NewBlock(meta, model.CurrentEncoding) require.NoError(t, err) dec := model.MustNewSegmentDecoder(model.CurrentEncoding) @@ -1736,7 +1737,7 @@ func runEventLinkInstrumentationSearchTest(t *testing.T, blockVersion string) { // Write to wal wal := w.WAL() - meta := &backend.BlockMeta{BlockID: uuid.New(), TenantID: testTenantID} + meta := &backend.BlockMeta{BlockID: uuid.UUID{UUID: google_uuid.New()}, TenantID: testTenantID} head, err := wal.NewBlock(meta, model.CurrentEncoding) require.NoError(t, err) dec := model.MustNewSegmentDecoder(model.CurrentEncoding) @@ -2207,7 +2208,7 @@ func TestWALBlockGetMetrics(t *testing.T) { r.EnablePolling(ctx, &mockJobSharder{}) wal := w.WAL() - meta := &backend.BlockMeta{BlockID: uuid.New(), TenantID: testTenantID} + meta := &backend.BlockMeta{BlockID: uuid.UUID{UUID: google_uuid.New()}, TenantID: testTenantID} head, err := wal.NewBlock(meta, model.CurrentEncoding) require.NoError(t, err) @@ -2265,7 +2266,7 @@ func TestSearchForTagsAndTagValues(t *testing.T) { r.EnablePolling(context.Background(), &mockJobSharder{}) - blockID := uuid.New() + blockID := uuid.UUID{UUID: google_uuid.New()} wal := w.WAL() diff --git a/tempodb/tempodb_test.go b/tempodb/tempodb_test.go index 625d8959ecd..cd8aa2a2c80 100644 --- a/tempodb/tempodb_test.go +++ b/tempodb/tempodb_test.go @@ -12,7 +12,7 @@ import ( "github.com/go-kit/log" "github.com/golang/protobuf/proto" //nolint:all - "github.com/google/uuid" + google_uuid "github.com/google/uuid" v2 "github.com/grafana/tempo/tempodb/encoding/v2" "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/assert" @@ -25,6 +25,7 @@ import ( "github.com/grafana/tempo/pkg/model/trace" "github.com/grafana/tempo/pkg/tempopb" "github.com/grafana/tempo/pkg/util/test" + "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/backend/local" "github.com/grafana/tempo/tempodb/encoding" @@ -165,8 +166,8 @@ func TestBlockSharding(t *testing.T) { assert.Len(t, blocks, 1) // check if it respects the blockstart/blockend params - case1: hit - blockStart := uuid.MustParse(BlockIDMin).String() - blockEnd := uuid.MustParse(BlockIDMax).String() + blockStart := google_uuid.MustParse(BlockIDMin).String() + blockEnd := google_uuid.MustParse(BlockIDMax).String() bFound, failedBlocks, err := r.Find(context.Background(), testTenantID, id, blockStart, blockEnd, 0, 0, common.DefaultSearchOptions()) assert.NoError(t, err) assert.Nil(t, failedBlocks) @@ -174,8 +175,8 @@ func TestBlockSharding(t *testing.T) { assert.True(t, proto.Equal(bFound[0], req)) // check if it respects the blockstart/blockend params - case2: miss - blockStart = uuid.MustParse(BlockIDMin).String() - blockEnd = uuid.MustParse(BlockIDMin).String() + blockStart = google_uuid.MustParse(BlockIDMin).String() + blockEnd = google_uuid.MustParse(BlockIDMin).String() bFound, failedBlocks, err = r.Find(context.Background(), testTenantID, id, blockStart, blockEnd, 0, 0, common.DefaultSearchOptions()) assert.NoError(t, err) assert.Nil(t, failedBlocks) @@ -231,13 +232,13 @@ func TestBlockCleanup(t *testing.T) { assert.Equal(t, 0, len(m)) } -func checkBlocklists(t *testing.T, expectedID uuid.UUID, expectedB int, expectedCB int, rw *readerWriter) { +func checkBlocklists(t *testing.T, expectedID google_uuid.UUID, expectedB int, expectedCB int, rw *readerWriter) { rw.pollBlocklist() blocklist := rw.blocklist.Metas(testTenantID) require.Len(t, blocklist, expectedB) - if expectedB > 0 && expectedID != uuid.Nil { - assert.Equal(t, expectedID, blocklist[0].BlockID) + if expectedB > 0 && expectedID != google_uuid.Nil { + assert.Equal(t, expectedID, blocklist[0].BlockID.UUID) } // confirm blocklists are in starttime ascending order @@ -249,8 +250,8 @@ func checkBlocklists(t *testing.T, expectedID uuid.UUID, expectedB int, expected compactedBlocklist := rw.blocklist.CompactedMetas(testTenantID) assert.Len(t, compactedBlocklist, expectedCB) - if expectedCB > 0 && expectedID != uuid.Nil { - assert.Equal(t, expectedID, compactedBlocklist[0].BlockID) + if expectedCB > 0 && expectedID != google_uuid.Nil { + assert.Equal(t, expectedID, compactedBlocklist[0].BlockID.UUID) } lastTime = time.Time{} @@ -264,8 +265,8 @@ func TestIncludeBlock(t *testing.T) { tests := []struct { name string searchID common.ID - blockStart uuid.UUID - blockEnd uuid.UUID + blockStart google_uuid.UUID + blockEnd google_uuid.UUID start int64 end int64 meta *backend.BlockMeta @@ -275,8 +276,8 @@ func TestIncludeBlock(t *testing.T) { { name: "include - duh", searchID: []byte{0x05}, - blockStart: uuid.MustParse(BlockIDMin), - blockEnd: uuid.MustParse(BlockIDMax), + blockStart: google_uuid.MustParse(BlockIDMin), + blockEnd: google_uuid.MustParse(BlockIDMax), meta: &backend.BlockMeta{ BlockID: uuid.MustParse("50000000-0000-0000-0000-000000000000"), }, @@ -287,8 +288,8 @@ func TestIncludeBlock(t *testing.T) { { name: "include - min id range", searchID: []byte{0x00}, - blockStart: uuid.MustParse(BlockIDMin), - blockEnd: uuid.MustParse(BlockIDMax), + blockStart: google_uuid.MustParse(BlockIDMin), + blockEnd: google_uuid.MustParse(BlockIDMax), meta: &backend.BlockMeta{ BlockID: uuid.MustParse("50000000-0000-0000-0000-000000000000"), }, @@ -299,8 +300,8 @@ func TestIncludeBlock(t *testing.T) { { name: "include - max id range", searchID: []byte{0x10}, - blockStart: uuid.MustParse(BlockIDMin), - blockEnd: uuid.MustParse(BlockIDMax), + blockStart: google_uuid.MustParse(BlockIDMin), + blockEnd: google_uuid.MustParse(BlockIDMax), meta: &backend.BlockMeta{ BlockID: uuid.MustParse("50000000-0000-0000-0000-000000000000"), }, @@ -311,8 +312,8 @@ func TestIncludeBlock(t *testing.T) { { name: "include - min block range", searchID: []byte{0x05}, - blockStart: uuid.MustParse("50000000-0000-0000-0000-000000000000"), - blockEnd: uuid.MustParse(BlockIDMax), + blockStart: google_uuid.MustParse("50000000-0000-0000-0000-000000000000"), + blockEnd: google_uuid.MustParse(BlockIDMax), meta: &backend.BlockMeta{ BlockID: uuid.MustParse("50000000-0000-0000-0000-000000000000"), }, @@ -323,8 +324,8 @@ func TestIncludeBlock(t *testing.T) { { name: "include - max block range", searchID: []byte{0x05}, - blockStart: uuid.MustParse(BlockIDMin), - blockEnd: uuid.MustParse("50000000-0000-0000-0000-000000000000"), + blockStart: google_uuid.MustParse(BlockIDMin), + blockEnd: google_uuid.MustParse("50000000-0000-0000-0000-000000000000"), meta: &backend.BlockMeta{ BlockID: uuid.MustParse("50000000-0000-0000-0000-000000000000"), StartTime: time.Unix(10000, 0), @@ -337,8 +338,8 @@ func TestIncludeBlock(t *testing.T) { { name: "include - max block range", searchID: []byte{0x05}, - blockStart: uuid.MustParse(BlockIDMin), - blockEnd: uuid.MustParse("50000000-0000-0000-0000-000000000000"), + blockStart: google_uuid.MustParse(BlockIDMin), + blockEnd: google_uuid.MustParse("50000000-0000-0000-0000-000000000000"), meta: &backend.BlockMeta{ BlockID: uuid.MustParse("50000000-0000-0000-0000-000000000000"), StartTime: time.Unix(1650285326, 0), @@ -351,8 +352,8 @@ func TestIncludeBlock(t *testing.T) { { name: "include - exact hit", searchID: []byte{0x05}, - blockStart: uuid.MustParse("50000000-0000-0000-0000-000000000000"), - blockEnd: uuid.MustParse("50000000-0000-0000-0000-000000000000"), + blockStart: google_uuid.MustParse("50000000-0000-0000-0000-000000000000"), + blockEnd: google_uuid.MustParse("50000000-0000-0000-0000-000000000000"), meta: &backend.BlockMeta{ BlockID: uuid.MustParse("50000000-0000-0000-0000-000000000000"), }, @@ -364,8 +365,8 @@ func TestIncludeBlock(t *testing.T) { { name: "exclude - duh", searchID: []byte{0x20}, - blockStart: uuid.MustParse("50000000-0000-0000-0000-000000000000"), - blockEnd: uuid.MustParse("51000000-0000-0000-0000-000000000000"), + blockStart: google_uuid.MustParse("50000000-0000-0000-0000-000000000000"), + blockEnd: google_uuid.MustParse("51000000-0000-0000-0000-000000000000"), meta: &backend.BlockMeta{ BlockID: uuid.MustParse("52000000-0000-0000-0000-000000000000"), }, @@ -392,8 +393,8 @@ func TestIncludeBlock(t *testing.T) { { name: "exclude - min block range", searchID: []byte{0x05}, - blockStart: uuid.MustParse("50000000-0000-0000-0000-000000000000"), - blockEnd: uuid.MustParse("51000000-0000-0000-0000-000000000000"), + blockStart: google_uuid.MustParse("50000000-0000-0000-0000-000000000000"), + blockEnd: google_uuid.MustParse("51000000-0000-0000-0000-000000000000"), meta: &backend.BlockMeta{ BlockID: uuid.MustParse("4FFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF"), }, @@ -401,8 +402,8 @@ func TestIncludeBlock(t *testing.T) { { name: "exclude - max block range", searchID: []byte{0x05}, - blockStart: uuid.MustParse("50000000-0000-0000-0000-000000000000"), - blockEnd: uuid.MustParse("51000000-0000-0000-0000-000000000000"), + blockStart: google_uuid.MustParse("50000000-0000-0000-0000-000000000000"), + blockEnd: google_uuid.MustParse("51000000-0000-0000-0000-000000000000"), meta: &backend.BlockMeta{ BlockID: uuid.MustParse("51000000-0000-0000-0000-000000000001"), }, @@ -426,8 +427,8 @@ func TestIncludeCompactedBlock(t *testing.T) { tests := []struct { name string searchID common.ID - blockStart uuid.UUID - blockEnd uuid.UUID + blockStart google_uuid.UUID + blockEnd google_uuid.UUID meta *backend.CompactedBlockMeta start int64 end int64 @@ -436,8 +437,8 @@ func TestIncludeCompactedBlock(t *testing.T) { { name: "include recent", searchID: []byte{0x05}, - blockStart: uuid.MustParse(BlockIDMin), - blockEnd: uuid.MustParse(BlockIDMax), + blockStart: google_uuid.MustParse(BlockIDMin), + blockEnd: google_uuid.MustParse(BlockIDMax), start: 0, end: 0, meta: &backend.CompactedBlockMeta{ @@ -451,8 +452,8 @@ func TestIncludeCompactedBlock(t *testing.T) { { name: "skip old", searchID: []byte{0x05}, - blockStart: uuid.MustParse(BlockIDMin), - blockEnd: uuid.MustParse(BlockIDMax), + blockStart: google_uuid.MustParse(BlockIDMin), + blockEnd: google_uuid.MustParse(BlockIDMax), start: 0, end: 0, meta: &backend.CompactedBlockMeta{ @@ -466,8 +467,8 @@ func TestIncludeCompactedBlock(t *testing.T) { { name: "skip recent but out of range", searchID: []byte{0x05}, - blockStart: uuid.MustParse("40000000-0000-0000-0000-000000000000"), - blockEnd: uuid.MustParse("50000000-0000-0000-0000-000000000000"), + blockStart: google_uuid.MustParse("40000000-0000-0000-0000-000000000000"), + blockEnd: google_uuid.MustParse("50000000-0000-0000-0000-000000000000"), start: 0, end: 0, meta: &backend.CompactedBlockMeta{ @@ -588,7 +589,7 @@ func testCompleteBlock(t *testing.T, from, to string) { rw := w.(*readerWriter) rw.cfg.Block.Version = to // now set it back so we cut blocks in the "to" format - blockID := uuid.New() + blockID := google_uuid.New() var dataEncoding string if from == v2.VersionString { From 3b175bc1eb7a10b85b2c546b8e4a3a6d868bfcde Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 11 Sep 2024 16:59:25 +0000 Subject: [PATCH 13/71] Update method style for uuid.New() --- tempodb/backend/v1.pb.go | 9 +++++---- tempodb/blocklist/poller_test.go | 4 ++-- tempodb/compactor_test.go | 10 +++++----- tempodb/encoding/vparquet2/compactor.go | 3 +-- tempodb/encoding/vparquet2/compactor_test.go | 3 +-- tempodb/encoding/vparquet3/compactor.go | 3 +-- tempodb/encoding/vparquet3/compactor_test.go | 3 +-- tempodb/encoding/vparquet4/compactor.go | 3 +-- tempodb/encoding/vparquet4/compactor_test.go | 3 +-- tempodb/retention_test.go | 5 ++--- tempodb/tempodb_search_test.go | 9 ++++----- 11 files changed, 24 insertions(+), 31 deletions(-) diff --git a/tempodb/backend/v1.pb.go b/tempodb/backend/v1.pb.go index 359b374f304..d634572c521 100644 --- a/tempodb/backend/v1.pb.go +++ b/tempodb/backend/v1.pb.go @@ -5,15 +5,16 @@ package backend import ( fmt "fmt" + io "io" + math "math" + math_bits "math/bits" + time "time" + _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" github_com_grafana_tempo_pkg_uuid "github.com/grafana/tempo/pkg/uuid" _ "google.golang.org/protobuf/types/known/timestamppb" - io "io" - math "math" - math_bits "math/bits" - time "time" ) // Reference imports to suppress errors if they are not otherwise used. diff --git a/tempodb/blocklist/poller_test.go b/tempodb/blocklist/poller_test.go index b40ca2d86f3..cc761dcd3e2 100644 --- a/tempodb/blocklist/poller_test.go +++ b/tempodb/blocklist/poller_test.go @@ -1045,7 +1045,7 @@ func newBlockMetas(count int) []*backend.BlockMeta { metas := make([]*backend.BlockMeta, count) for i := 0; i < count; i++ { metas[i] = &backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.New()}, + BlockID: uuid.New(), } } @@ -1057,7 +1057,7 @@ func newCompactedMetas(count int) []*backend.CompactedBlockMeta { for i := 0; i < count; i++ { metas[i] = &backend.CompactedBlockMeta{ BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.New()}, + BlockID: uuid.New(), }, } } diff --git a/tempodb/compactor_test.go b/tempodb/compactor_test.go index e26cb118125..1b1bf543503 100644 --- a/tempodb/compactor_test.go +++ b/tempodb/compactor_test.go @@ -132,7 +132,7 @@ func testCompactionRoundtrip(t *testing.T, targetBlockVersion string) { allIds := make([]common.ID, 0, blockCount*recordCount) for i := 0; i < blockCount; i++ { - blockID := uuid.UUID{UUID: google_uuid.New()} + blockID := uuid.New() meta := &backend.BlockMeta{BlockID: blockID, TenantID: testTenantID, DataEncoding: model.CurrentEncoding} head, err := wal.NewBlock(meta, model.CurrentEncoding) require.NoError(t, err) @@ -304,7 +304,7 @@ func testSameIDCompaction(t *testing.T, targetBlockVersion string) { // and write them to different blocks for i := 0; i < blockCount; i++ { - blockID := uuid.UUID{UUID: google_uuid.New()} + blockID := uuid.New() meta := &backend.BlockMeta{BlockID: blockID, TenantID: testTenantID, DataEncoding: v1.Encoding} head, err := wal.NewBlock(meta, v1.Encoding) require.NoError(t, err) @@ -703,7 +703,7 @@ func testCompactionDropsTraces(t *testing.T, targetBlockVersion string) { allIDs := make([]common.ID, 0, recordCount) // write a bunch of dummy data - blockID := uuid.UUID{UUID: google_uuid.New()} + blockID := uuid.New() meta := &backend.BlockMeta{BlockID: blockID, TenantID: testTenantID, DataEncoding: v1.Encoding} head, err := wal.NewBlock(meta, v1.Encoding) require.NoError(t, err) @@ -790,7 +790,7 @@ func cutTestBlockWithTraces(t testing.TB, w Writer, tenantID string, data []test wal := w.WAL() - meta := &backend.BlockMeta{BlockID: uuid.UUID{UUID: google_uuid.New()}, TenantID: testTenantID} + meta := &backend.BlockMeta{BlockID: uuid.New(), TenantID: testTenantID} head, err := wal.NewBlock(meta, model.CurrentEncoding) require.NoError(t, err) @@ -810,7 +810,7 @@ func cutTestBlocks(t testing.TB, w Writer, tenantID string, blockCount int, reco wal := w.WAL() for i := 0; i < blockCount; i++ { - meta := &backend.BlockMeta{BlockID: uuid.UUID{UUID: google_uuid.New()}, TenantID: tenantID} + meta := &backend.BlockMeta{BlockID: uuid.New(), TenantID: tenantID} head, err := wal.NewBlock(meta, model.CurrentEncoding) require.NoError(t, err) diff --git a/tempodb/encoding/vparquet2/compactor.go b/tempodb/encoding/vparquet2/compactor.go index 35a345b80aa..c0ba0237727 100644 --- a/tempodb/encoding/vparquet2/compactor.go +++ b/tempodb/encoding/vparquet2/compactor.go @@ -11,7 +11,6 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" - google_uuid "github.com/google/uuid" tempoUtil "github.com/grafana/tempo/pkg/util" "github.com/parquet-go/parquet-go" @@ -151,7 +150,7 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, if currentBlock == nil { // Start with a copy and then customize newMeta := &backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.New()}, + BlockID: uuid.New(), TenantID: inputs[0].TenantID, CompactionLevel: uint32(nextCompactionLevel), TotalObjects: int32(recordsPerBlock), // Just an estimate diff --git a/tempodb/encoding/vparquet2/compactor_test.go b/tempodb/encoding/vparquet2/compactor_test.go index e3085c92688..85c9da43c3e 100644 --- a/tempodb/encoding/vparquet2/compactor_test.go +++ b/tempodb/encoding/vparquet2/compactor_test.go @@ -8,7 +8,6 @@ import ( "testing" "github.com/go-kit/log" - google_uuid "github.com/google/uuid" tempoUtil "github.com/grafana/tempo/pkg/util" "github.com/parquet-go/parquet-go" @@ -114,7 +113,7 @@ func BenchmarkCompactorDupes(b *testing.B) { func createTestBlock(t testing.TB, ctx context.Context, cfg *common.BlockConfig, r backend.Reader, w backend.Writer, traceCount, batchCount, spanCount int) *backend.BlockMeta { inMeta := &backend.BlockMeta{ TenantID: tenantID, - BlockID: uuid.UUID{UUID: google_uuid.New()}, + BlockID: uuid.New(), TotalObjects: int32(traceCount), } diff --git a/tempodb/encoding/vparquet3/compactor.go b/tempodb/encoding/vparquet3/compactor.go index ae0f9ac38d2..f0652f2871e 100644 --- a/tempodb/encoding/vparquet3/compactor.go +++ b/tempodb/encoding/vparquet3/compactor.go @@ -11,7 +11,6 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" - google_uuid "github.com/google/uuid" tempoUtil "github.com/grafana/tempo/pkg/util" "github.com/parquet-go/parquet-go" @@ -157,7 +156,7 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, if currentBlock == nil { // Start with a copy and then customize newMeta := &backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.New()}, + BlockID: uuid.New(), TenantID: inputs[0].TenantID, CompactionLevel: uint32(nextCompactionLevel), TotalObjects: int32(recordsPerBlock), // Just an estimate diff --git a/tempodb/encoding/vparquet3/compactor_test.go b/tempodb/encoding/vparquet3/compactor_test.go index 082980d30fd..d4141495cc8 100644 --- a/tempodb/encoding/vparquet3/compactor_test.go +++ b/tempodb/encoding/vparquet3/compactor_test.go @@ -8,7 +8,6 @@ import ( "testing" "github.com/go-kit/log" - google_uuid "github.com/google/uuid" "github.com/parquet-go/parquet-go" "github.com/stretchr/testify/require" @@ -114,7 +113,7 @@ func BenchmarkCompactorDupes(b *testing.B) { func createTestBlock(t testing.TB, ctx context.Context, cfg *common.BlockConfig, r backend.Reader, w backend.Writer, traceCount, batchCount, spanCount, replicationFactor int, dc backend.DedicatedColumns) *backend.BlockMeta { inMeta := &backend.BlockMeta{ TenantID: tenantID, - BlockID: uuid.UUID{UUID: google_uuid.New()}, + BlockID: uuid.New(), TotalObjects: int32(traceCount), ReplicationFactor: uint32(replicationFactor), DedicatedColumns: dc, diff --git a/tempodb/encoding/vparquet4/compactor.go b/tempodb/encoding/vparquet4/compactor.go index 58c5139aba6..52005669e5a 100644 --- a/tempodb/encoding/vparquet4/compactor.go +++ b/tempodb/encoding/vparquet4/compactor.go @@ -11,7 +11,6 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" - google_uuid "github.com/google/uuid" tempoUtil "github.com/grafana/tempo/pkg/util" "github.com/parquet-go/parquet-go" @@ -157,7 +156,7 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, if currentBlock == nil { // Start with a copy and then customize newMeta := &backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.New()}, + BlockID: uuid.New(), TenantID: inputs[0].TenantID, CompactionLevel: nextCompactionLevel, TotalObjects: recordsPerBlock, // Just an estimate diff --git a/tempodb/encoding/vparquet4/compactor_test.go b/tempodb/encoding/vparquet4/compactor_test.go index b5bf0f6b02a..5c5fb91df29 100644 --- a/tempodb/encoding/vparquet4/compactor_test.go +++ b/tempodb/encoding/vparquet4/compactor_test.go @@ -8,7 +8,6 @@ import ( "testing" "github.com/go-kit/log" - google_uuid "github.com/google/uuid" "github.com/parquet-go/parquet-go" "github.com/stretchr/testify/require" @@ -114,7 +113,7 @@ func BenchmarkCompactorDupes(b *testing.B) { func createTestBlock(t testing.TB, ctx context.Context, cfg *common.BlockConfig, r backend.Reader, w backend.Writer, traceCount, batchCount, spanCount, replicationFactor int, dc backend.DedicatedColumns) *backend.BlockMeta { inMeta := &backend.BlockMeta{ TenantID: tenantID, - BlockID: uuid.UUID{UUID: google_uuid.New()}, + BlockID: uuid.New(), TotalObjects: int32(traceCount), ReplicationFactor: uint32(replicationFactor), DedicatedColumns: dc, diff --git a/tempodb/retention_test.go b/tempodb/retention_test.go index 32fb252e048..588ec71508f 100644 --- a/tempodb/retention_test.go +++ b/tempodb/retention_test.go @@ -7,7 +7,6 @@ import ( "time" "github.com/go-kit/log" - google_uuid "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -54,7 +53,7 @@ func TestRetention(t *testing.T) { r.EnablePolling(ctx, &mockJobSharder{}) - blockID := uuid.UUID{UUID: google_uuid.New()} + blockID := uuid.New() wal := w.WAL() assert.NoError(t, err) @@ -121,7 +120,7 @@ func TestRetentionUpdatesBlocklistImmediately(t *testing.T) { wal := w.WAL() assert.NoError(t, err) - blockID := uuid.UUID{UUID: google_uuid.New()} + blockID := uuid.New() meta := &backend.BlockMeta{BlockID: blockID, TenantID: testTenantID} head, err := wal.NewBlock(meta, model.CurrentEncoding) diff --git a/tempodb/tempodb_search_test.go b/tempodb/tempodb_search_test.go index 6c4ccf98024..07e2c8dcc7d 100644 --- a/tempodb/tempodb_search_test.go +++ b/tempodb/tempodb_search_test.go @@ -13,7 +13,6 @@ import ( "time" "github.com/go-kit/log" - google_uuid "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -1621,7 +1620,7 @@ func runCompleteBlockSearchTest(t *testing.T, blockVersion string, runners ...ru // Write to wal wal := w.WAL() - meta := &backend.BlockMeta{BlockID: uuid.UUID{UUID: google_uuid.New()}, TenantID: testTenantID, DedicatedColumns: dc} + meta := &backend.BlockMeta{BlockID: uuid.New(), TenantID: testTenantID, DedicatedColumns: dc} head, err := wal.NewBlock(meta, model.CurrentEncoding) require.NoError(t, err) dec := model.MustNewSegmentDecoder(model.CurrentEncoding) @@ -1737,7 +1736,7 @@ func runEventLinkInstrumentationSearchTest(t *testing.T, blockVersion string) { // Write to wal wal := w.WAL() - meta := &backend.BlockMeta{BlockID: uuid.UUID{UUID: google_uuid.New()}, TenantID: testTenantID} + meta := &backend.BlockMeta{BlockID: uuid.New(), TenantID: testTenantID} head, err := wal.NewBlock(meta, model.CurrentEncoding) require.NoError(t, err) dec := model.MustNewSegmentDecoder(model.CurrentEncoding) @@ -2208,7 +2207,7 @@ func TestWALBlockGetMetrics(t *testing.T) { r.EnablePolling(ctx, &mockJobSharder{}) wal := w.WAL() - meta := &backend.BlockMeta{BlockID: uuid.UUID{UUID: google_uuid.New()}, TenantID: testTenantID} + meta := &backend.BlockMeta{BlockID: uuid.New(), TenantID: testTenantID} head, err := wal.NewBlock(meta, model.CurrentEncoding) require.NoError(t, err) @@ -2266,7 +2265,7 @@ func TestSearchForTagsAndTagValues(t *testing.T) { r.EnablePolling(context.Background(), &mockJobSharder{}) - blockID := uuid.UUID{UUID: google_uuid.New()} + blockID := uuid.New() wal := w.WAL() From e0f256e0fdb2bb840b2572b882f573a7acb41c63 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 11 Sep 2024 17:05:47 +0000 Subject: [PATCH 14/71] Update method style for uuid.MustParse() --- tempodb/backend/block_meta_test.go | 2 +- tempodb/blocklist/list_test.go | 108 +++++----- tempodb/blocklist/poller_test.go | 14 +- tempodb/compaction_block_selector_test.go | 234 +++++++++++----------- 4 files changed, 179 insertions(+), 179 deletions(-) diff --git a/tempodb/backend/block_meta_test.go b/tempodb/backend/block_meta_test.go index 4ea09299236..a6e7a267da6 100644 --- a/tempodb/backend/block_meta_test.go +++ b/tempodb/backend/block_meta_test.go @@ -100,7 +100,7 @@ func TestBlockMetaParsing(t *testing.T) { meta := BlockMeta{ Version: "vParquet3", - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), TenantID: "single-tenant", StartTime: timeParse("2021-01-01T00:00:00.0000000Z"), EndTime: timeParse("2021-01-02T00:00:00.0000000Z"), diff --git a/tempodb/blocklist/list_test.go b/tempodb/blocklist/list_test.go index 9793fed56f7..263bc9d3a59 100644 --- a/tempodb/blocklist/list_test.go +++ b/tempodb/blocklist/list_test.go @@ -30,12 +30,12 @@ func TestApplyPollResults(t *testing.T) { metas: PerTenant{ "test": []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, }, "test2": []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, }, }, @@ -47,19 +47,19 @@ func TestApplyPollResults(t *testing.T) { "test": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, }, }, "test2": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, }, { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), }, }, }, @@ -71,12 +71,12 @@ func TestApplyPollResults(t *testing.T) { metas: PerTenant{ "test": []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, }, "blerg": []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, }, }, @@ -84,19 +84,19 @@ func TestApplyPollResults(t *testing.T) { "test": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, }, }, "test2": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, }, { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), }, }, }, @@ -145,13 +145,13 @@ func TestUpdate(t *testing.T) { existing: nil, add: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, }, remove: nil, expected: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, }, }, @@ -159,21 +159,21 @@ func TestUpdate(t *testing.T) { name: "add to existing", existing: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, }, add: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), }, }, remove: nil, expected: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), }, }, }, @@ -183,7 +183,7 @@ func TestUpdate(t *testing.T) { add: nil, remove: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), }, }, expected: nil, @@ -192,14 +192,14 @@ func TestUpdate(t *testing.T) { name: "remove nil", existing: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), }, }, add: nil, remove: nil, expected: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), }, }, }, @@ -207,21 +207,21 @@ func TestUpdate(t *testing.T) { name: "remove existing", existing: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), }, }, add: nil, remove: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), }, }, }, @@ -229,18 +229,18 @@ func TestUpdate(t *testing.T) { name: "remove no match", existing: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, }, add: nil, remove: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, }, }, @@ -248,28 +248,28 @@ func TestUpdate(t *testing.T) { name: "add and remove", existing: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), }, }, add: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), }, }, remove: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), }, }, }, @@ -277,24 +277,24 @@ func TestUpdate(t *testing.T) { name: "add already exists", existing: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, }, add: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), }, }, remove: nil, expected: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), }, }, }, @@ -336,14 +336,14 @@ func TestUpdateCompacted(t *testing.T) { add: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, }, }, expected: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, }, }, @@ -353,26 +353,26 @@ func TestUpdateCompacted(t *testing.T) { existing: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, }, }, add: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), }, }, }, expected: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, }, { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), }, }, }, @@ -382,31 +382,31 @@ func TestUpdateCompacted(t *testing.T) { existing: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, }, }, add: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, }, { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), }, }, }, expected: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, }, { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), }, }, }, @@ -416,38 +416,38 @@ func TestUpdateCompacted(t *testing.T) { existing: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, }, { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), }, }, }, add: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), }, }, }, remove: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), }, }, }, expected: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, }, { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), }, }, }, diff --git a/tempodb/blocklist/poller_test.go b/tempodb/blocklist/poller_test.go index cc761dcd3e2..e8c8f9fdfd0 100644 --- a/tempodb/blocklist/poller_test.go +++ b/tempodb/blocklist/poller_test.go @@ -38,9 +38,9 @@ func (m *mockJobSharder) Owns(_ string) bool { return m.owns } func TestTenantIndexBuilder(t *testing.T) { var ( - one = uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")} - two = uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")} - three = uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")} + one = uuid.MustParse("00000000-0000-0000-0000-000000000001") + two = uuid.MustParse("00000000-0000-0000-0000-000000000002") + three = uuid.MustParse("00000000-0000-0000-0000-000000000003") ) tests := []struct { @@ -290,7 +290,7 @@ func TestTenantIndexFallback(t *testing.T) { } func TestPollBlock(t *testing.T) { - one := uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")} + one := uuid.MustParse("00000000-0000-0000-0000-000000000001") tests := []struct { name string @@ -659,9 +659,9 @@ func TestPollTolerateConsecutiveErrors(t *testing.T) { } func TestPollComparePreviousResults(t *testing.T) { - zero := uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")} - aaa := uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-00000000000A")} - eff := uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-00000000000F")} + zero := uuid.MustParse("00000000-0000-0000-0000-000000000000") + aaa := uuid.MustParse("00000000-0000-0000-0000-00000000000A") + eff := uuid.MustParse("00000000-0000-0000-0000-00000000000F") testCases := []struct { name string diff --git a/tempodb/compaction_block_selector_test.go b/tempodb/compaction_block_selector_test.go index 7f225a6b20d..ca8475435cf 100644 --- a/tempodb/compaction_block_selector_test.go +++ b/tempodb/compaction_block_selector_test.go @@ -41,21 +41,21 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "only two", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, }, }, @@ -65,17 +65,17 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "choose smallest two", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), TotalObjects: 0, EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), TotalObjects: 1, EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), TotalObjects: 0, EndTime: now, }, @@ -83,12 +83,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { maxInputBlocks: 2, expected: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), TotalObjects: 0, EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), TotalObjects: 0, EndTime: now, }, @@ -99,40 +99,40 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "different windows", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now.Add(-timeWindow), }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now.Add(-timeWindow), }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, }, }, expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 0), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now.Add(-timeWindow), }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now.Add(-timeWindow), }, }, @@ -142,22 +142,22 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "different sizes", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, TotalObjects: 15, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, TotalObjects: 1, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now, TotalObjects: 3, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, TotalObjects: 12, }, @@ -165,12 +165,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { maxInputBlocks: 2, expected: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, TotalObjects: 1, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now, TotalObjects: 3, }, @@ -178,12 +178,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 0), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, TotalObjects: 12, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, TotalObjects: 15, }, @@ -194,43 +194,43 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "different compaction lvls", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, }, }, expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 0), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now, CompactionLevel: 1, }, @@ -241,48 +241,48 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "active time window vs not", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now.Add(-activeWindowDuration - time.Minute), CompactionLevel: 1, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now.Add(-activeWindowDuration - time.Minute), CompactionLevel: 0, }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now, }, }, expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 0), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now.Add(-activeWindowDuration - time.Minute), CompactionLevel: 0, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now.Add(-activeWindowDuration - time.Minute), CompactionLevel: 1, }, @@ -293,50 +293,50 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "choose lowest compaction level", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now.Add(-timeWindow), }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000005")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000005"), EndTime: now.Add(-timeWindow), }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now, }, }, expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 0), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now.Add(-timeWindow), }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000005")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000005"), EndTime: now.Add(-timeWindow), }, }, @@ -346,11 +346,11 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "doesn't choose across time windows", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now.Add(-timeWindow), }, }, @@ -363,12 +363,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "doesn't exceed max compaction objects", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), TotalObjects: 99, EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), TotalObjects: 2, EndTime: now, }, @@ -382,12 +382,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "doesn't exceed max block size", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), Size_: 50, EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), Size_: 51, EndTime: now, }, @@ -402,29 +402,29 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "Returns as many blocks as possible without exceeding max compaction objects", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), TotalObjects: 50, EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), TotalObjects: 50, EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), TotalObjects: 50, EndTime: now, }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), TotalObjects: 50, EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), TotalObjects: 50, EndTime: now, }, @@ -438,29 +438,29 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { maxBlockBytes: 100, blocklist: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), Size_: 50, EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), Size_: 50, EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), Size_: 1, EndTime: now, }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), Size_: 50, EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), Size_: 50, EndTime: now, }, @@ -475,44 +475,44 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { maxInputBlocks: 3, blocklist: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, TotalObjects: 1, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, TotalObjects: 2, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now, TotalObjects: 3, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, TotalObjects: 4, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000005")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000005"), EndTime: now, TotalObjects: 5, }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, TotalObjects: 1, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, TotalObjects: 2, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now, TotalObjects: 3, }, @@ -520,12 +520,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 0), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, TotalObjects: 4, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000005")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000005"), EndTime: now, TotalObjects: 5, }, @@ -536,11 +536,11 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "honors minimum block count", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, }, }, @@ -555,22 +555,22 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "can choose blocks not at the lowest compaction level", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, CompactionLevel: 0, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, CompactionLevel: 1, }, @@ -579,17 +579,17 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { maxInputBlocks: 3, expected: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, CompactionLevel: 1, }, @@ -602,12 +602,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "doesn't select blocks in last active window", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now.Add(-activeWindowDuration), CompactionLevel: 0, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now.Add(-activeWindowDuration), CompactionLevel: 0, }, @@ -617,12 +617,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "don't compact across dataEncodings", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000000")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now, DataEncoding: "bar", }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, DataEncoding: "foo", }, @@ -633,12 +633,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "ensures blocks of different versions are not compacted", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, Version: "v2", }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, Version: "vParquet3", }, @@ -652,34 +652,34 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "ensures blocks of the same version are compacted", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, Version: "v2", }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, Version: "vParquet3", }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now, Version: "v2", }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, Version: "vParquet3", }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, Version: "v2", }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now, Version: "v2", }, @@ -687,12 +687,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 0), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, Version: "vParquet3", }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, Version: "vParquet3", }, @@ -703,28 +703,28 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "blocks with different dedicated columns are not selected together", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, DedicatedColumns: backend.DedicatedColumns{ {Scope: "span", Name: "foo", Type: "int"}, }, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, DedicatedColumns: backend.DedicatedColumns{ {Scope: "span", Name: "foo", Type: "string"}, }, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now, DedicatedColumns: backend.DedicatedColumns{ {Scope: "span", Name: "foo", Type: "int"}, }, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, DedicatedColumns: backend.DedicatedColumns{ {Scope: "span", Name: "foo", Type: "string"}, @@ -733,14 +733,14 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { }, expected: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, DedicatedColumns: backend.DedicatedColumns{ {Scope: "span", Name: "foo", Type: "int"}, }, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now, DedicatedColumns: backend.DedicatedColumns{ {Scope: "span", Name: "foo", Type: "int"}, @@ -750,14 +750,14 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 0), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, DedicatedColumns: backend.DedicatedColumns{ {Scope: "span", Name: "foo", Type: "string"}, }, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, DedicatedColumns: backend.DedicatedColumns{ {Scope: "span", Name: "foo", Type: "string"}, @@ -770,34 +770,34 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "blocks are grouped by replication factor", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, ReplicationFactor: 1, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, ReplicationFactor: 3, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now, ReplicationFactor: 1, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, ReplicationFactor: 3, }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000001")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, ReplicationFactor: 1, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000003")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now, ReplicationFactor: 1, }, @@ -805,12 +805,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 1), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000002")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, ReplicationFactor: 3, }, { - BlockID: uuid.UUID{UUID: google_uuid.MustParse("00000000-0000-0000-0000-000000000004")}, + BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, ReplicationFactor: 3, }, From e7a69347373b532befeb7e714edc83262556b434 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 11 Sep 2024 17:06:24 +0000 Subject: [PATCH 15/71] Add uuid.From helper --- pkg/uuid/uuid.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/uuid/uuid.go b/pkg/uuid/uuid.go index a62d6eb7513..5f2c594e423 100644 --- a/pkg/uuid/uuid.go +++ b/pkg/uuid/uuid.go @@ -35,6 +35,10 @@ func Parse(s string) (UUID, error) { return UUID{u}, nil } +func From(u google_uuid.UUID) UUID { + return UUID{u} +} + func (u UUID) Marshal() ([]byte, error) { return u.MarshalBinary() } From 59ea4e1bc58552abccee42afd614d80adf235971 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 11 Sep 2024 17:09:45 +0000 Subject: [PATCH 16/71] Update modules for UUID and proto struct types --- modules/frontend/cache_keys_test.go | 2 +- .../frontend/metrics_query_range_sharder.go | 4 +-- modules/frontend/search_handlers_test.go | 14 ++++---- modules/frontend/search_sharder.go | 8 ++--- modules/frontend/search_sharder_test.go | 24 +++++++------- modules/frontend/tag_handlers_test.go | 4 +-- modules/frontend/tag_sharder.go | 4 +-- modules/frontend/tag_sharder_test.go | 2 +- .../processor/localblocks/processor.go | 29 ++++++++-------- .../processor/localblocks/query_range.go | 8 ++--- modules/ingester/flush.go | 2 +- modules/ingester/ingester.go | 6 ++-- modules/ingester/instance.go | 33 ++++++++++--------- modules/ingester/instance_search.go | 6 ++-- modules/ingester/local_block.go | 4 +-- modules/querier/querier.go | 10 +++--- modules/querier/querier_query_range.go | 4 +-- 17 files changed, 83 insertions(+), 81 deletions(-) diff --git a/modules/frontend/cache_keys_test.go b/modules/frontend/cache_keys_test.go index 44845898fcc..d875a3966dd 100644 --- a/modules/frontend/cache_keys_test.go +++ b/modules/frontend/cache_keys_test.go @@ -4,8 +4,8 @@ import ( "testing" "time" - "github.com/google/uuid" "github.com/grafana/tempo/pkg/tempopb" + "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/stretchr/testify/require" ) diff --git a/modules/frontend/metrics_query_range_sharder.go b/modules/frontend/metrics_query_range_sharder.go index 9ee0987a482..6ffb54dd6af 100644 --- a/modules/frontend/metrics_query_range_sharder.go +++ b/modules/frontend/metrics_query_range_sharder.go @@ -194,7 +194,7 @@ func (s *queryRangeSharder) backendRequests(ctx context.Context, tenantID string if int(b.TotalRecords)%p != 0 { totalJobs++ } - totalBlockBytes += b.Size + totalBlockBytes += b.Size_ } go func() { @@ -259,7 +259,7 @@ func (s *queryRangeSharder) buildBackendRequests(ctx context.Context, tenantID s PagesToSearch: uint32(pages), Version: m.Version, Encoding: m.Encoding.String(), - Size_: m.Size, + Size_: m.Size_, FooterSize: m.FooterSize, // DedicatedColumns: dc, for perf reason we pass dedicated columns json in directly to not have to realloc object -> proto -> json Exemplars: exemplars, diff --git a/modules/frontend/search_handlers_test.go b/modules/frontend/search_handlers_test.go index 38582b5a0ec..935dfee1d93 100644 --- a/modules/frontend/search_handlers_test.go +++ b/modules/frontend/search_handlers_test.go @@ -18,7 +18,6 @@ import ( "github.com/gogo/protobuf/jsonpb" "github.com/gogo/protobuf/proto" "github.com/gogo/status" - "github.com/google/uuid" "github.com/grafana/dskit/user" "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/require" @@ -34,6 +33,7 @@ import ( "github.com/grafana/tempo/pkg/traceql" "github.com/grafana/tempo/pkg/util" "github.com/grafana/tempo/pkg/util/test" + "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb" "github.com/grafana/tempo/tempodb/backend" ) @@ -558,7 +558,7 @@ func TestSearchAccessesCache(t *testing.T) { meta := &backend.BlockMeta{ StartTime: time.Unix(15, 0), EndTime: time.Unix(16, 0), - Size: defaultTargetBytesPerRequest, + Size_: defaultTargetBytesPerRequest, TotalRecords: 1, BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000123"), } @@ -676,7 +676,7 @@ func BenchmarkSearchPipeline(b *testing.B) { rdr.metas = append(rdr.metas, &backend.BlockMeta{ StartTime: time.Unix(15, 0), EndTime: time.Unix(16, 0), - Size: defaultTargetBytesPerRequest, + Size_: defaultTargetBytesPerRequest, TotalRecords: 1, BlockID: uuid.MustParse(fmt.Sprintf("00000000-0000-0000-0000-%012d", i)), }) @@ -735,14 +735,14 @@ func frontendWithSettings(t require.TestingT, next http.RoundTripper, rdr tempod { StartTime: time.Unix(1100, 0), EndTime: time.Unix(1200, 0), - Size: defaultTargetBytesPerRequest * 2, + Size_: defaultTargetBytesPerRequest * 2, TotalRecords: 2, BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), }, { StartTime: time.Unix(1100, 0), EndTime: time.Unix(1200, 0), - Size: defaultTargetBytesPerRequest * 2, + Size_: defaultTargetBytesPerRequest * 2, TotalRecords: 2, BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, @@ -750,7 +750,7 @@ func frontendWithSettings(t require.TestingT, next http.RoundTripper, rdr tempod { StartTime: time.Unix(1100, 0), EndTime: time.Unix(1200, 0), - Size: defaultTargetBytesPerRequest * 2, + Size_: defaultTargetBytesPerRequest * 2, TotalRecords: 2, BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), ReplicationFactor: 1, @@ -758,7 +758,7 @@ func frontendWithSettings(t require.TestingT, next http.RoundTripper, rdr tempod { StartTime: time.Unix(1100, 0), EndTime: time.Unix(1200, 0), - Size: defaultTargetBytesPerRequest * 2, + Size_: defaultTargetBytesPerRequest * 2, TotalRecords: 2, BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), ReplicationFactor: 1, diff --git a/modules/frontend/search_sharder.go b/modules/frontend/search_sharder.go index deced98fa48..9799a18d242 100644 --- a/modules/frontend/search_sharder.go +++ b/modules/frontend/search_sharder.go @@ -186,7 +186,7 @@ func (s *asyncSearchSharder) backendRequests(ctx context.Context, tenantID strin if int(b.TotalRecords)%p != 0 { totalJobs++ } - totalBlockBytes += b.Size + totalBlockBytes += b.Size_ } go func() { @@ -329,7 +329,7 @@ func buildBackendRequests(ctx context.Context, tenantID string, parent *http.Req TotalRecords: m.TotalRecords, DataEncoding: m.DataEncoding, Version: m.Version, - Size_: m.Size, + Size_: m.Size_, FooterSize: m.FooterSize, // DedicatedColumns: dc, for perf reason we pass dedicated columns json in directly to not have to realloc object -> proto -> json }, dedColsJSON) @@ -380,11 +380,11 @@ func hashForSearchRequest(searchRequest *tempopb.SearchRequest) uint64 { // that should be searched per query. This value is based on the target number of bytes // 0 is returned if there is no valid answer func pagesPerRequest(m *backend.BlockMeta, bytesPerRequest int) int { - if m.Size == 0 || m.TotalRecords == 0 { + if m.Size_ == 0 || m.TotalRecords == 0 { return 0 } - bytesPerPage := m.Size / uint64(m.TotalRecords) + bytesPerPage := m.Size_ / uint64(m.TotalRecords) if bytesPerPage == 0 { return 0 } diff --git a/modules/frontend/search_sharder_test.go b/modules/frontend/search_sharder_test.go index 5d18d869817..9329f73ef13 100644 --- a/modules/frontend/search_sharder_test.go +++ b/modules/frontend/search_sharder_test.go @@ -16,7 +16,6 @@ import ( "github.com/go-kit/log" "github.com/gogo/protobuf/jsonpb" - "github.com/google/uuid" "github.com/grafana/dskit/user" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/common/model" @@ -29,6 +28,7 @@ import ( "github.com/grafana/tempo/pkg/api" "github.com/grafana/tempo/pkg/tempopb" "github.com/grafana/tempo/pkg/traceql" + "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/blocklist" @@ -105,7 +105,7 @@ func TestBuildBackendRequests(t *testing.T) { { metas: []*backend.BlockMeta{ { - Size: 1000, + Size_: 1000, BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), }, }, @@ -116,7 +116,7 @@ func TestBuildBackendRequests(t *testing.T) { targetBytesPerRequest: 1000, metas: []*backend.BlockMeta{ { - Size: 1000, + Size_: 1000, TotalRecords: 100, BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), DataEncoding: "json", @@ -134,7 +134,7 @@ func TestBuildBackendRequests(t *testing.T) { targetBytesPerRequest: 1000, metas: []*backend.BlockMeta{ { - Size: 1000, + Size_: 1000, TotalRecords: 10, BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), Encoding: backend.EncNone, @@ -154,7 +154,7 @@ func TestBuildBackendRequests(t *testing.T) { targetBytesPerRequest: 1, metas: []*backend.BlockMeta{ { - Size: 1000, + Size_: 1000, TotalRecords: 3, BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), }, @@ -170,7 +170,7 @@ func TestBuildBackendRequests(t *testing.T) { targetBytesPerRequest: 1000, metas: []*backend.BlockMeta{ { - Size: 1000, + Size_: 1000, TotalRecords: 100, BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), }, @@ -184,7 +184,7 @@ func TestBuildBackendRequests(t *testing.T) { targetBytesPerRequest: 900, metas: []*backend.BlockMeta{ { - Size: 1000, + Size_: 1000, TotalRecords: 100, BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), }, @@ -199,12 +199,12 @@ func TestBuildBackendRequests(t *testing.T) { targetBytesPerRequest: 900, metas: []*backend.BlockMeta{ { - Size: 1000, + Size_: 1000, TotalRecords: 100, BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), }, { - Size: 1000, + Size_: 1000, TotalRecords: 200, BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), }, @@ -244,10 +244,10 @@ func TestBuildBackendRequests(t *testing.T) { } func TestBackendRequests(t *testing.T) { - bm := backend.NewBlockMeta("test", uuid.New(), "wdwad", backend.EncGZIP, "asdf") + bm := backend.NewBlockMeta("test", uuid.New().UUID, "wdwad", backend.EncGZIP, "asdf") bm.StartTime = time.Unix(100, 0) bm.EndTime = time.Unix(200, 0) - bm.Size = defaultTargetBytesPerRequest * 2 + bm.Size_ = defaultTargetBytesPerRequest * 2 bm.TotalRecords = 2 s := &asyncSearchSharder{ @@ -663,7 +663,7 @@ func TestTotalJobsIncludesIngester(t *testing.T) { { StartTime: time.Unix(now, 0), EndTime: time.Unix(now, 0), - Size: defaultTargetBytesPerRequest * 2, + Size_: defaultTargetBytesPerRequest * 2, TotalRecords: 2, BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), }, diff --git a/modules/frontend/tag_handlers_test.go b/modules/frontend/tag_handlers_test.go index e806cdcfbd1..9fd3174c6fd 100644 --- a/modules/frontend/tag_handlers_test.go +++ b/modules/frontend/tag_handlers_test.go @@ -14,11 +14,11 @@ import ( "github.com/gogo/protobuf/jsonpb" "github.com/gogo/protobuf/proto" "github.com/gogo/status" - "github.com/google/uuid" "github.com/grafana/dskit/user" "github.com/grafana/tempo/pkg/cache" "github.com/grafana/tempo/pkg/tempopb" "github.com/grafana/tempo/pkg/util/test" + "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/segmentio/fasthash/fnv1a" "github.com/stretchr/testify/require" @@ -432,7 +432,7 @@ func TestSearchTagsV2AccessesCache(t *testing.T) { meta := &backend.BlockMeta{ StartTime: time.Unix(15, 0), EndTime: time.Unix(16, 0), - Size: defaultTargetBytesPerRequest, + Size_: defaultTargetBytesPerRequest, TotalRecords: 1, BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000123"), } diff --git a/modules/frontend/tag_sharder.go b/modules/frontend/tag_sharder.go index 9cd3b749247..8328ad2b58d 100644 --- a/modules/frontend/tag_sharder.go +++ b/modules/frontend/tag_sharder.go @@ -66,7 +66,7 @@ func (r *tagsSearchRequest) buildTagSearchBlockRequest(subR *http.Request, block TotalRecords: m.TotalRecords, DataEncoding: m.DataEncoding, Version: m.Version, - Size_: m.Size, + Size_: m.Size_, FooterSize: m.FooterSize, }) } @@ -121,7 +121,7 @@ func (r *tagValueSearchRequest) buildTagSearchBlockRequest(subR *http.Request, b TotalRecords: m.TotalRecords, DataEncoding: m.DataEncoding, Version: m.Version, - Size_: m.Size, + Size_: m.Size_, FooterSize: m.FooterSize, }) } diff --git a/modules/frontend/tag_sharder_test.go b/modules/frontend/tag_sharder_test.go index 0e961e4fcdb..dfc1460c000 100644 --- a/modules/frontend/tag_sharder_test.go +++ b/modules/frontend/tag_sharder_test.go @@ -89,7 +89,7 @@ func TestTagsBackendRequests(t *testing.T) { bm := backend.NewBlockMeta("test", uuid.New(), "wdwad", backend.EncGZIP, "asdf") bm.StartTime = time.Unix(100, 0) bm.EndTime = time.Unix(200, 0) - bm.Size = defaultTargetBytesPerRequest * 2 + bm.Size_ = defaultTargetBytesPerRequest * 2 bm.TotalRecords = 2 s := &searchTagSharder{ diff --git a/modules/generator/processor/localblocks/processor.go b/modules/generator/processor/localblocks/processor.go index 7d54ca8de3c..e1e0e43a14b 100644 --- a/modules/generator/processor/localblocks/processor.go +++ b/modules/generator/processor/localblocks/processor.go @@ -13,7 +13,7 @@ import ( kitlog "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/golang/groupcache/lru" - "github.com/google/uuid" + google_uuid "github.com/google/uuid" "github.com/grafana/tempo/modules/ingester" "github.com/grafana/tempo/pkg/flushqueues" "github.com/grafana/tempo/tempodb" @@ -26,6 +26,7 @@ import ( "github.com/grafana/tempo/pkg/traceql" "github.com/grafana/tempo/pkg/traceqlmetrics" "github.com/grafana/tempo/pkg/util/log" + "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/encoding" "github.com/grafana/tempo/tempodb/encoding/common" @@ -59,8 +60,8 @@ type Processor struct { blocksMtx sync.RWMutex headBlock common.WALBlock - walBlocks map[uuid.UUID]common.WALBlock - completeBlocks map[uuid.UUID]*ingester.LocalBlock + walBlocks map[google_uuid.UUID]common.WALBlock + completeBlocks map[google_uuid.UUID]*ingester.LocalBlock lastCutTime time.Time flushqueue *flushqueues.PriorityQueue @@ -96,8 +97,8 @@ func New(cfg Config, tenant string, wal *wal.WAL, writer tempodb.Writer, overrid walW: backend.NewWriter(wal.LocalBackend()), overrides: overrides, enc: enc, - walBlocks: map[uuid.UUID]common.WALBlock{}, - completeBlocks: map[uuid.UUID]*ingester.LocalBlock{}, + walBlocks: map[google_uuid.UUID]common.WALBlock{}, + completeBlocks: map[google_uuid.UUID]*ingester.LocalBlock{}, flushqueue: flushqueues.NewPriorityQueue(metricFlushQueueSize.WithLabelValues(tenant)), liveTraces: newLiveTraces(), traceSizes: newTraceSizes(), @@ -351,11 +352,11 @@ func (p *Processor) completeBlock() error { p.blocksMtx.Lock() defer p.blocksMtx.Unlock() - p.completeBlocks[newMeta.BlockID] = ingester.NewLocalBlock(ctx, newBlock, p.wal.LocalBackend()) + p.completeBlocks[newMeta.BlockID.UUID] = ingester.NewLocalBlock(ctx, newBlock, p.wal.LocalBackend()) metricCompletedBlocks.WithLabelValues(p.tenant).Inc() // Queue for flushing - if _, err := p.flushqueue.Enqueue(newFlushOp(newMeta.BlockID)); err != nil { + if _, err := p.flushqueue.Enqueue(newFlushOp(newMeta.BlockID.UUID)); err != nil { _ = level.Error(p.logger).Log("msg", "local blocks processor failed to enqueue block for flushing", "err", err) } @@ -363,12 +364,12 @@ func (p *Processor) completeBlock() error { if err != nil { return err } - delete(p.walBlocks, b.BlockMeta().BlockID) + delete(p.walBlocks, b.BlockMeta().BlockID.UUID) return nil } -func (p *Processor) flushBlock(id uuid.UUID) error { +func (p *Processor) flushBlock(id google_uuid.UUID) error { p.blocksMtx.RLock() completeBlock := p.completeBlocks[id] p.blocksMtx.RUnlock() @@ -679,7 +680,7 @@ func (p *Processor) cutBlocks(immediate bool) error { return fmt.Errorf("failed to flush head block: %w", err) } - p.walBlocks[p.headBlock.BlockMeta().BlockID] = p.headBlock + p.walBlocks[p.headBlock.BlockMeta().BlockID.UUID] = p.headBlock metricCutBlocks.WithLabelValues(p.tenant).Inc() err = p.resetHeadBlock() @@ -710,7 +711,7 @@ func (p *Processor) reloadBlocks() error { meta := blk.BlockMeta() if meta.TenantID == p.tenant { level.Info(p.logger).Log("msg", "reloading wal block", "block", meta.BlockID.String()) - p.walBlocks[blk.BlockMeta().BlockID] = blk + p.walBlocks[blk.BlockMeta().BlockID.UUID] = blk } } level.Info(p.logger).Log("msg", "reloaded wal blocks", "count", len(p.walBlocks)) @@ -795,7 +796,7 @@ func (p *Processor) recordBlockBytes() { sum += b.DataLength() } for _, b := range p.completeBlocks { - sum += b.BlockMeta().Size + sum += b.BlockMeta().Size_ } metricBlockSize.WithLabelValues(p.tenant).Set(float64(sum)) @@ -878,13 +879,13 @@ func filterBatches(batches []*v1.ResourceSpans) []*v1.ResourceSpans { } type flushOp struct { - blockID uuid.UUID + blockID google_uuid.UUID at time.Time // When to execute attempts int bo time.Duration } -func newFlushOp(blockID uuid.UUID) *flushOp { +func newFlushOp(blockID google_uuid.UUID) *flushOp { return &flushOp{ blockID: blockID, at: time.Now(), diff --git a/modules/generator/processor/localblocks/query_range.go b/modules/generator/processor/localblocks/query_range.go index ec8ab286605..23b64b358ef 100644 --- a/modules/generator/processor/localblocks/query_range.go +++ b/modules/generator/processor/localblocks/query_range.go @@ -152,7 +152,7 @@ func (p *Processor) queryRangeWALBlock(ctx context.Context, b common.WALBlock, e m := b.BlockMeta() ctx, span := tracer.Start(ctx, "Processor.QueryRange.WALBlock", trace.WithAttributes( attribute.String("block", m.BlockID.String()), - attribute.Int64("blockSize", int64(m.Size)), + attribute.Int64("blockSize", int64(m.Size_)), )) defer span.End() @@ -167,7 +167,7 @@ func (p *Processor) queryRangeCompleteBlock(ctx context.Context, b *ingester.Loc m := b.BlockMeta() ctx, span := tracer.Start(ctx, "Processor.QueryRange.CompleteBlock", trace.WithAttributes( attribute.String("block", m.BlockID.String()), - attribute.Int64("blockSize", int64(m.Size)), + attribute.Int64("blockSize", int64(m.Size_)), )) defer span.End() @@ -224,7 +224,7 @@ func (p *Processor) queryRangeCacheGet(ctx context.Context, m *backend.BlockMeta name := fmt.Sprintf("cache_query_range_%v.buf", hash) - data, err := p.walR.Read(ctx, name, m.BlockID, m.TenantID, nil) + data, err := p.walR.Read(ctx, name, m.BlockID.UUID, m.TenantID, nil) if err != nil { if errors.Is(err, backend.ErrDoesNotExist) { // Not cached, but return the name/keypath so it can be set after @@ -248,7 +248,7 @@ func (p *Processor) queryRangeCacheSet(ctx context.Context, m *backend.BlockMeta return err } - return p.walW.Write(ctx, name, m.BlockID, m.TenantID, data, nil) + return p.walW.Write(ctx, name, m.BlockID.UUID, m.TenantID, data, nil) } func queryRangeHashForBlock(req tempopb.QueryRangeRequest) uint64 { diff --git a/modules/ingester/flush.go b/modules/ingester/flush.go index c31f0f0941d..ebb39ec00cc 100644 --- a/modules/ingester/flush.go +++ b/modules/ingester/flush.go @@ -327,7 +327,7 @@ func (i *Ingester) handleFlush(ctx context.Context, userID string, blockID uuid. start := time.Now() err = i.store.WriteBlock(ctx, block) metricFlushDuration.Observe(time.Since(start).Seconds()) - metricFlushSize.Observe(float64(block.BlockMeta().Size)) + metricFlushSize.Observe(float64(block.BlockMeta().Size_)) if err != nil { sp.SetStatus(codes.Error, "") sp.RecordError(err) diff --git a/modules/ingester/ingester.go b/modules/ingester/ingester.go index 93cd301e93c..e27cc7a5bf6 100644 --- a/modules/ingester/ingester.go +++ b/modules/ingester/ingester.go @@ -389,7 +389,7 @@ func (i *Ingester) replayWal() error { // deleted (because it was rescanned above). This can happen for reasons // such as a crash or restart. In this situation we err on the side of // caution and replay the wal block. - err = instance.local.ClearBlock(b.BlockMeta().BlockID, tenantID) + err = instance.local.ClearBlock(b.BlockMeta().BlockID.UUID, tenantID) if err != nil { return err } @@ -398,7 +398,7 @@ func (i *Ingester) replayWal() error { i.enqueue(&flushOp{ kind: opKindComplete, userID: tenantID, - blockID: b.BlockMeta().BlockID, + blockID: b.BlockMeta().BlockID.UUID, }, i.replayJitter) } @@ -445,7 +445,7 @@ func (i *Ingester) rediscoverLocalBlocks() error { i.enqueue(&flushOp{ kind: opKindFlush, userID: t, - blockID: b.BlockMeta().BlockID, + blockID: b.BlockMeta().BlockID.UUID, }, i.replayJitter) } } diff --git a/modules/ingester/instance.go b/modules/ingester/instance.go index dc11ceee304..9408374c04d 100644 --- a/modules/ingester/instance.go +++ b/modules/ingester/instance.go @@ -14,7 +14,7 @@ import ( "github.com/go-kit/log/level" "github.com/gogo/status" - "github.com/google/uuid" + google_uuid "github.com/google/uuid" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "go.uber.org/atomic" @@ -25,6 +25,7 @@ import ( "github.com/grafana/tempo/pkg/model/trace" "github.com/grafana/tempo/pkg/tempopb" "github.com/grafana/tempo/pkg/util/log" + "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/pkg/validation" "github.com/grafana/tempo/tempodb" "github.com/grafana/tempo/tempodb/backend" @@ -271,12 +272,12 @@ func (i *instance) CutCompleteTraces(cutoff time.Duration, immediate bool) error // CutBlockIfReady cuts a completingBlock from the HeadBlock if ready. // Returns the ID of a block if one was cut or a nil ID if one was not cut, along with the error (if any). -func (i *instance) CutBlockIfReady(maxBlockLifetime time.Duration, maxBlockBytes uint64, immediate bool) (uuid.UUID, error) { +func (i *instance) CutBlockIfReady(maxBlockLifetime time.Duration, maxBlockBytes uint64, immediate bool) (google_uuid.UUID, error) { i.headBlockMtx.Lock() defer i.headBlockMtx.Unlock() if i.headBlock == nil || i.headBlock.DataLength() == 0 { - return uuid.Nil, nil + return google_uuid.Nil, nil } now := time.Now() @@ -285,7 +286,7 @@ func (i *instance) CutBlockIfReady(maxBlockLifetime time.Duration, maxBlockBytes // Final flush err := i.headBlock.Flush() if err != nil { - return uuid.Nil, fmt.Errorf("failed to flush head block: %w", err) + return google_uuid.Nil, fmt.Errorf("failed to flush head block: %w", err) } completingBlock := i.headBlock @@ -303,21 +304,21 @@ func (i *instance) CutBlockIfReady(maxBlockLifetime time.Duration, maxBlockBytes err = i.resetHeadBlock() if err != nil { - return uuid.Nil, fmt.Errorf("failed to resetHeadBlock: %w", err) + return google_uuid.Nil, fmt.Errorf("failed to resetHeadBlock: %w", err) } - return completingBlock.BlockMeta().BlockID, nil + return completingBlock.BlockMeta().BlockID.UUID, nil } - return uuid.Nil, nil + return google_uuid.Nil, nil } // CompleteBlock moves a completingBlock to a completeBlock. The new completeBlock has the same ID. -func (i *instance) CompleteBlock(blockID uuid.UUID) error { +func (i *instance) CompleteBlock(blockID google_uuid.UUID) error { i.blocksMtx.Lock() var completingBlock common.WALBlock for _, iterBlock := range i.completingBlocks { - if iterBlock.BlockMeta().BlockID == blockID { + if iterBlock.BlockMeta().BlockID.UUID == blockID { completingBlock = iterBlock break } @@ -344,13 +345,13 @@ func (i *instance) CompleteBlock(blockID uuid.UUID) error { return nil } -func (i *instance) ClearCompletingBlock(blockID uuid.UUID) error { +func (i *instance) ClearCompletingBlock(blockID google_uuid.UUID) error { i.blocksMtx.Lock() defer i.blocksMtx.Unlock() var completingBlock common.WALBlock for j, iterBlock := range i.completingBlocks { - if iterBlock.BlockMeta().BlockID == blockID { + if iterBlock.BlockMeta().BlockID.UUID == blockID { completingBlock = iterBlock i.completingBlocks = append(i.completingBlocks[:j], i.completingBlocks[j+1:]...) break @@ -365,12 +366,12 @@ func (i *instance) ClearCompletingBlock(blockID uuid.UUID) error { } // GetBlockToBeFlushed gets a list of blocks that can be flushed to the backend. -func (i *instance) GetBlockToBeFlushed(blockID uuid.UUID) *LocalBlock { +func (i *instance) GetBlockToBeFlushed(blockID google_uuid.UUID) *LocalBlock { i.blocksMtx.RLock() defer i.blocksMtx.RUnlock() for _, c := range i.completeBlocks { - if c.BlockMeta().BlockID == blockID && c.FlushedTime().IsZero() { + if c.BlockMeta().BlockID.UUID == blockID && c.FlushedTime().IsZero() { return c } } @@ -393,7 +394,7 @@ func (i *instance) ClearFlushedBlocks(completeBlockTimeout time.Duration) error if flushedTime.Add(completeBlockTimeout).Before(time.Now()) { i.completeBlocks = append(i.completeBlocks[:idx], i.completeBlocks[idx+1:]...) - err = i.local.ClearBlock(b.BlockMeta().BlockID, i.instanceID) + err = i.local.ClearBlock(b.BlockMeta().BlockID.UUID, i.instanceID) if err == nil { metricBlocksClearedTotal.Inc() } @@ -585,11 +586,11 @@ func (i *instance) rediscoverLocalBlocks(ctx context.Context) ([]*LocalBlock, er return nil, err } - hasWal := func(id uuid.UUID) bool { + hasWal := func(id google_uuid.UUID) bool { i.blocksMtx.RLock() defer i.blocksMtx.RUnlock() for _, b := range i.completingBlocks { - if b.BlockMeta().BlockID == id { + if b.BlockMeta().BlockID.UUID == id { return true } } diff --git a/modules/ingester/instance_search.go b/modules/ingester/instance_search.go index b0f7f711b1d..a34bc8c94f7 100644 --- a/modules/ingester/instance_search.go +++ b/modules/ingester/instance_search.go @@ -119,7 +119,7 @@ func (i *instance) Search(ctx context.Context, req *tempopb.SearchRequest) (*tem i.headBlockMtx.RLock() span.AddEvent("acquired headblock mtx") if includeBlock(i.headBlock.BlockMeta(), req) { - search(i.headBlock.BlockMeta().BlockID, i.headBlock, "headBlock") + search(i.headBlock.BlockMeta().BlockID.UUID, i.headBlock, "headBlock") } i.headBlockMtx.RUnlock() if err := anyErr.Load(); err != nil { @@ -150,7 +150,7 @@ func (i *instance) Search(ctx context.Context, req *tempopb.SearchRequest) (*tem wg.Add(1) go func(b common.WALBlock) { defer wg.Done() - search(b.BlockMeta().BlockID, b, "completingBlock") + search(b.BlockMeta().BlockID.UUID, b, "completingBlock") }(b) } @@ -161,7 +161,7 @@ func (i *instance) Search(ctx context.Context, req *tempopb.SearchRequest) (*tem wg.Add(1) go func(b *LocalBlock) { defer wg.Done() - search(b.BlockMeta().BlockID, b, "completeBlock") + search(b.BlockMeta().BlockID.UUID, b, "completeBlock") }(b) } diff --git a/modules/ingester/local_block.go b/modules/ingester/local_block.go index 614f337cfea..75d9ade1a3e 100644 --- a/modules/ingester/local_block.go +++ b/modules/ingester/local_block.go @@ -41,7 +41,7 @@ func NewLocalBlock(ctx context.Context, existingBlock common.BackendBlock, l *lo writer: backend.NewWriter(l), } - flushedBytes, err := c.reader.Read(ctx, nameFlushed, c.BlockMeta().BlockID, c.BlockMeta().TenantID, nil) + flushedBytes, err := c.reader.Read(ctx, nameFlushed, c.BlockMeta().BlockID.UUID, c.BlockMeta().TenantID, nil) if err == nil { flushedTime := time.Time{} err = flushedTime.UnmarshalText(flushedBytes) @@ -107,7 +107,7 @@ func (c *LocalBlock) SetFlushed(ctx context.Context) error { return fmt.Errorf("error marshalling flush time to text: %w", err) } - err = c.writer.Write(ctx, nameFlushed, c.BlockMeta().BlockID, c.BlockMeta().TenantID, flushedBytes, nil) + err = c.writer.Write(ctx, nameFlushed, c.BlockMeta().BlockID.UUID, c.BlockMeta().TenantID, flushedBytes, nil) if err != nil { return fmt.Errorf("error writing ingester block flushed file: %w", err) } diff --git a/modules/querier/querier.go b/modules/querier/querier.go index 85a455ab673..a0ae76e0dfa 100644 --- a/modules/querier/querier.go +++ b/modules/querier/querier.go @@ -10,7 +10,6 @@ import ( "time" "github.com/go-kit/log/level" - "github.com/google/uuid" httpgrpc_server "github.com/grafana/dskit/httpgrpc/server" "github.com/grafana/dskit/ring" ring_client "github.com/grafana/dskit/ring/client" @@ -40,6 +39,7 @@ import ( "github.com/grafana/tempo/pkg/traceqlmetrics" "github.com/grafana/tempo/pkg/util" "github.com/grafana/tempo/pkg/util/log" + "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/pkg/validation" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/encoding/common" @@ -866,7 +866,7 @@ func (q *Querier) internalSearchBlock(ctx context.Context, req *tempopb.SearchBl Version: req.Version, TenantID: tenantID, Encoding: enc, - Size: req.Size_, + Size_: req.Size_, IndexPageSize: req.IndexPageSize, TotalRecords: req.TotalRecords, BlockID: blockID, @@ -929,7 +929,7 @@ func (q *Querier) internalTagsSearchBlockV2(ctx context.Context, req *tempopb.Se Version: req.Version, TenantID: tenantID, Encoding: enc, - Size: req.Size_, + Size_: req.Size_, IndexPageSize: req.IndexPageSize, TotalRecords: req.TotalRecords, BlockID: blockID, @@ -1017,7 +1017,7 @@ func (q *Querier) internalTagValuesSearchBlock(ctx context.Context, req *tempopb Version: req.Version, TenantID: tenantID, Encoding: enc, - Size: req.Size_, + Size_: req.Size_, IndexPageSize: req.IndexPageSize, TotalRecords: req.TotalRecords, BlockID: blockID, @@ -1065,7 +1065,7 @@ func (q *Querier) internalTagValuesSearchBlockV2(ctx context.Context, req *tempo Version: req.Version, TenantID: tenantID, Encoding: enc, - Size: req.Size_, + Size_: req.Size_, IndexPageSize: req.IndexPageSize, TotalRecords: req.TotalRecords, BlockID: blockID, diff --git a/modules/querier/querier_query_range.go b/modules/querier/querier_query_range.go index cfc8df2ceba..a95d00980e6 100644 --- a/modules/querier/querier_query_range.go +++ b/modules/querier/querier_query_range.go @@ -6,13 +6,13 @@ import ( "time" "github.com/go-kit/log/level" - "github.com/google/uuid" "github.com/grafana/dskit/ring" "github.com/grafana/dskit/user" "github.com/grafana/tempo/pkg/tempopb" v1 "github.com/grafana/tempo/pkg/tempopb/common/v1" "github.com/grafana/tempo/pkg/traceql" "github.com/grafana/tempo/pkg/util/log" + "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/encoding/common" ) @@ -87,7 +87,7 @@ func (q *Querier) queryBlock(ctx context.Context, req *tempopb.QueryRangeRequest // TotalRecords: req.TotalRecords, BlockID: blockID, // DataEncoding: req.DataEncoding, - Size: req.Size_, + Size_: req.Size_, FooterSize: req.FooterSize, DedicatedColumns: dc, } From 7e898df7dae17854d25973be297e0ab9ec02d77d Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 11 Sep 2024 17:35:43 +0000 Subject: [PATCH 17/71] Update poller integration test for UUID --- integration/poller/poller_test.go | 33 ++++++++++++++++--------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/integration/poller/poller_test.go b/integration/poller/poller_test.go index 79a08d8fad3..a2e97655097 100644 --- a/integration/poller/poller_test.go +++ b/integration/poller/poller_test.go @@ -12,7 +12,7 @@ import ( "time" "github.com/go-kit/log" - "github.com/google/uuid" + google_uuid "github.com/google/uuid" "github.com/grafana/e2e" "github.com/grafana/tempo/integration/util" "github.com/stretchr/testify/assert" @@ -22,6 +22,7 @@ import ( "github.com/grafana/tempo/cmd/tempo/app" e2eBackend "github.com/grafana/tempo/integration/e2e/backend" "github.com/grafana/tempo/pkg/blockboundary" + "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/backend/azure" "github.com/grafana/tempo/tempodb/backend/gcs" @@ -161,7 +162,7 @@ func TestPollerOwnership(t *testing.T) { bb := blockboundary.CreateBlockBoundaries(listBlockConcurrency) tenantCount := 250 - tenantExpected := map[string][]uuid.UUID{} + tenantExpected := map[string][]google_uuid.UUID{} // Push some data to a few tenants for i := 0; i < tenantCount; i++ { @@ -188,9 +189,9 @@ func TestPollerOwnership(t *testing.T) { for testTenant, expected := range tenantExpected { metas := l.Metas(testTenant) - actual := []uuid.UUID{} + actual := []google_uuid.UUID{} for _, m := range metas { - actual = append(actual, m.BlockID) + actual = append(actual, m.BlockID.UUID) } sort.Slice(actual, func(i, j int) bool { return actual[i].String() < actual[j].String() }) @@ -369,9 +370,9 @@ func TestTenantDeletion(t *testing.T) { } } -func found(id uuid.UUID, blockMetas []*backend.BlockMeta) bool { +func found(id google_uuid.UUID, blockMetas []*backend.BlockMeta) bool { for _, b := range blockMetas { - if b.BlockID == id { + if b.BlockID.UUID == id { return true } } @@ -379,11 +380,11 @@ func found(id uuid.UUID, blockMetas []*backend.BlockMeta) bool { return false } -func writeTenantBlocks(t *testing.T, w backend.Writer, tenant string, blockIDs []uuid.UUID) { +func writeTenantBlocks(t *testing.T, w backend.Writer, tenant string, blockIDs []google_uuid.UUID) { var err error for _, b := range blockIDs { meta := &backend.BlockMeta{ - BlockID: b, + BlockID: uuid.From(b), TenantID: tenant, } @@ -446,43 +447,43 @@ func writeBadBlockFiles(t *testing.T, ww backend.RawWriter, rr backend.RawReader t.Logf("items: %v", found) } -func pushBlocksToTenant(t *testing.T, tenant string, bb [][]byte, w backend.Writer) []uuid.UUID { +func pushBlocksToTenant(t *testing.T, tenant string, bb [][]byte, w backend.Writer) []google_uuid.UUID { // Randomly pick a block boundary r := mathrand.IntN(len(bb)) base := bb[r] t.Logf("base: %v", base) - expected := []uuid.UUID{} + expected := []google_uuid.UUID{} // Include the min and max in each tenant for testing - expected = append(expected, uuid.MustParse("00000000-0000-0000-0000-000000000000")) - expected = append(expected, uuid.MustParse("ffffffff-ffff-ffff-ffff-ffffffffffff")) + expected = append(expected, google_uuid.MustParse("00000000-0000-0000-0000-000000000000")) + expected = append(expected, google_uuid.MustParse("ffffffff-ffff-ffff-ffff-ffffffffffff")) // If we are above zero, then we have room to decrement if r > 0 { decrementUUIDBytes(base) - expected = append(expected, uuid.UUID(base)) + expected = append(expected, google_uuid.UUID(base)) } // If we are n-1 then we have room to increment if r < len(bb)-1 { // Grab the one after the boundary incrementUUIDBytes(base) - expected = append(expected, uuid.UUID(base)) + expected = append(expected, google_uuid.UUID(base)) } // If we are n-2 then we have room to increment again if r < len(bb)-2 { // Grab the one after the boundary incrementUUIDBytes(base) - expected = append(expected, uuid.UUID(base)) + expected = append(expected, google_uuid.UUID(base)) } // If we are n-3 then we have room to increment again if r < len(bb)-3 { // Grab the one after the boundary incrementUUIDBytes(base) - expected = append(expected, uuid.UUID(base)) + expected = append(expected, google_uuid.UUID(base)) } // Write the blocks using the expectaed block IDs From fc66397e7c30e0ede2e255742e1a2e3877d05fdd Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 11 Sep 2024 17:36:15 +0000 Subject: [PATCH 18/71] Update tempo-cli for UUID and proto struct type changes --- cmd/tempo-cli/cmd-analyse-block.go | 6 +++--- cmd/tempo-cli/cmd-analyse-blocks.go | 2 +- cmd/tempo-cli/cmd-list-block.go | 2 +- cmd/tempo-cli/cmd-list-blocks.go | 8 ++++---- cmd/tempo-cli/cmd-list-column.go | 2 +- cmd/tempo-cli/cmd-list-compactionsummary.go | 16 ++++++++-------- cmd/tempo-cli/cmd-migrate-tenant.go | 4 ++-- cmd/tempo-cli/cmd-rewrite-blocks.go | 2 +- cmd/tempo-cli/cmd-view-pq-schema.go | 2 +- cmd/tempo-cli/shared.go | 9 ++++----- 10 files changed, 26 insertions(+), 27 deletions(-) diff --git a/cmd/tempo-cli/cmd-analyse-block.go b/cmd/tempo-cli/cmd-analyse-block.go index 04e70ba2839..88a694317a1 100644 --- a/cmd/tempo-cli/cmd-analyse-block.go +++ b/cmd/tempo-cli/cmd-analyse-block.go @@ -111,7 +111,7 @@ func (cmd *analyseBlockCmd) Run(ctx *globalOptions) error { return blockSum.print(cmd.NumAttr, cmd.GenerateJsonnet, cmd.SimpleSummary, cmd.PrintFullSummary) } -func processBlock(r backend.Reader, tenantID, blockID string, maxStartTime, minStartTime time.Time, minCompactionLvl uint8) (*blockSummary, error) { +func processBlock(r backend.Reader, tenantID, blockID string, maxStartTime, minStartTime time.Time, minCompactionLvl uint32) (*blockSummary, error) { id := uuid.MustParse(blockID) meta, err := r.BlockMeta(context.TODO(), id, tenantID) @@ -143,9 +143,9 @@ func processBlock(r backend.Reader, tenantID, blockID string, maxStartTime, minS return nil, nil } - br := tempo_io.NewBufferedReaderAt(reader, int64(meta.Size), 2*1024*1024, 64) // 128 MB memory buffering + br := tempo_io.NewBufferedReaderAt(reader, int64(meta.Size_), 2*1024*1024, 64) // 128 MB memory buffering - pf, err := parquet.OpenFile(br, int64(meta.Size), parquet.SkipBloomFilters(true), parquet.SkipPageIndex(true)) + pf, err := parquet.OpenFile(br, int64(meta.Size_), parquet.SkipBloomFilters(true), parquet.SkipPageIndex(true)) if err != nil { return nil, err } diff --git a/cmd/tempo-cli/cmd-analyse-blocks.go b/cmd/tempo-cli/cmd-analyse-blocks.go index e5bceee17cd..f24668042a5 100644 --- a/cmd/tempo-cli/cmd-analyse-blocks.go +++ b/cmd/tempo-cli/cmd-analyse-blocks.go @@ -60,7 +60,7 @@ func (cmd *analyseBlocksCmd) Run(ctx *globalOptions) error { continue } - blockSum, err := processBlock(r, cmd.TenantID, block.String(), maxStartTime, minStartTime, uint8(cmd.MinCompactionLevel)) + blockSum, err := processBlock(r, cmd.TenantID, block.String(), maxStartTime, minStartTime, uint32(cmd.MinCompactionLevel)) if err != nil { if !errors.Is(err, backend.ErrDoesNotExist) { return err diff --git a/cmd/tempo-cli/cmd-list-block.go b/cmd/tempo-cli/cmd-list-block.go index 550f2113be6..9b37523ca7b 100644 --- a/cmd/tempo-cli/cmd-list-block.go +++ b/cmd/tempo-cli/cmd-list-block.go @@ -73,7 +73,7 @@ func dumpBlock(r tempodb_backend.Reader, c tempodb_backend.Compactor, tenantID s fmt.Println("ID : ", unifiedMeta.BlockID) fmt.Println("Version : ", unifiedMeta.Version) fmt.Println("Total Objects : ", unifiedMeta.TotalObjects) - fmt.Println("Data Size : ", humanize.Bytes(unifiedMeta.Size)) + fmt.Println("Data Size : ", humanize.Bytes(unifiedMeta.Size_)) fmt.Println("Encoding : ", unifiedMeta.Encoding) fmt.Println("Level : ", unifiedMeta.CompactionLevel) fmt.Println("Window : ", unifiedMeta.window) diff --git a/cmd/tempo-cli/cmd-list-blocks.go b/cmd/tempo-cli/cmd-list-blocks.go index b6207af7afd..bfd936974bb 100644 --- a/cmd/tempo-cli/cmd-list-blocks.go +++ b/cmd/tempo-cli/cmd-list-blocks.go @@ -56,9 +56,9 @@ func displayResults(results []blockStats, windowDuration time.Duration, includeC case "lvl": s = strconv.Itoa(int(r.CompactionLevel)) case "objects": - s = strconv.Itoa(r.TotalObjects) + s = strconv.Itoa(int(r.TotalObjects)) case "size": - s = fmt.Sprintf("%v", humanize.Bytes(r.Size)) + s = fmt.Sprintf("%v", humanize.Bytes(r.Size_)) case "encoding": s = r.Encoding.String() case "vers": @@ -89,8 +89,8 @@ func displayResults(results []blockStats, windowDuration time.Duration, includeC } out = append(out, line) - totalObjects += r.TotalObjects - totalBytes += r.Size + totalObjects += int(r.TotalObjects) + totalBytes += r.Size_ } footer := make([]string, 0) diff --git a/cmd/tempo-cli/cmd-list-column.go b/cmd/tempo-cli/cmd-list-column.go index ffd3ea5ad52..3b45d3d46ea 100644 --- a/cmd/tempo-cli/cmd-list-column.go +++ b/cmd/tempo-cli/cmd-list-column.go @@ -33,7 +33,7 @@ func (cmd *listColumnCmd) Run(ctx *globalOptions) error { } rr := vparquet3.NewBackendReaderAt(context.Background(), r, vparquet3.DataFileName, meta) - pf, err := parquet.OpenFile(rr, int64(meta.Size)) + pf, err := parquet.OpenFile(rr, int64(meta.Size_)) if err != nil { return err } diff --git a/cmd/tempo-cli/cmd-list-compactionsummary.go b/cmd/tempo-cli/cmd-list-compactionsummary.go index 9ee7f69401e..9ebdffd7887 100644 --- a/cmd/tempo-cli/cmd-list-compactionsummary.go +++ b/cmd/tempo-cli/cmd-list-compactionsummary.go @@ -61,24 +61,24 @@ func displayCompactionSummary(results []blockStats) { sizeSum := uint64(0) sizeMin := uint64(0) sizeMax := uint64(0) - countSum := 0 - countMin := 0 - countMax := 0 + countSum := int32(0) + countMin := int32(0) + countMax := int32(0) countBloomShards := 0 var newest time.Time var oldest time.Time for _, r := range resultsByLevel[l] { - sizeSum += r.Size + sizeSum += r.Size_ countSum += r.TotalObjects countBloomShards += int(r.BloomShardCount) - if r.Size < sizeMin || sizeMin == 0 { - sizeMin = r.Size + if r.Size_ < sizeMin || sizeMin == 0 { + sizeMin = r.Size_ } - if r.Size > sizeMax { - sizeMax = r.Size + if r.Size_ > sizeMax { + sizeMax = r.Size_ } if r.TotalObjects < countMin || countMin == 0 { countMin = r.TotalObjects diff --git a/cmd/tempo-cli/cmd-migrate-tenant.go b/cmd/tempo-cli/cmd-migrate-tenant.go index a3c9f48ea03..7386051e9bc 100644 --- a/cmd/tempo-cli/cmd-migrate-tenant.go +++ b/cmd/tempo-cli/cmd-migrate-tenant.go @@ -49,7 +49,7 @@ blocks: for _, sourceBlockMeta := range sourceTenantIndex.Meta { // check for collisions for _, uuidDest := range blocksDest { - if sourceBlockMeta.BlockID == uuidDest { + if sourceBlockMeta.BlockID.UUID == uuidDest { fmt.Printf("UUID %s exists in source and destination, skipping block\n", sourceBlockMeta.BlockID) continue blocks } @@ -70,7 +70,7 @@ blocks: } copiedBlocks++ - copiedSize += sourceBlockMeta.Size + copiedSize += sourceBlockMeta.Size_ } fmt.Printf("Finished migrating data. Copied %d blocks, %s\n", copiedBlocks, humanize.Bytes(copiedSize)) diff --git a/cmd/tempo-cli/cmd-rewrite-blocks.go b/cmd/tempo-cli/cmd-rewrite-blocks.go index 929a267131c..15df12144c5 100644 --- a/cmd/tempo-cli/cmd-rewrite-blocks.go +++ b/cmd/tempo-cli/cmd-rewrite-blocks.go @@ -82,7 +82,7 @@ func (cmd *dropTraceCmd) Run(ctx *globalOptions) error { fmt.Println("marking old blocks compacted") for _, block := range blocks { fmt.Printf(" marking %v\n", block.BlockID) - err = c.MarkBlockCompacted(block.BlockID, block.TenantID) + err = c.MarkBlockCompacted(block.BlockID.UUID, block.TenantID) if err != nil { return err } diff --git a/cmd/tempo-cli/cmd-view-pq-schema.go b/cmd/tempo-cli/cmd-view-pq-schema.go index d709ea064a7..3ff8f76140d 100644 --- a/cmd/tempo-cli/cmd-view-pq-schema.go +++ b/cmd/tempo-cli/cmd-view-pq-schema.go @@ -37,7 +37,7 @@ func (cmd *viewSchemaCmd) Run(ctx *globalOptions) error { fmt.Printf("%+v\n", meta) rr := vparquet3.NewBackendReaderAt(context.Background(), r, vparquet3.DataFileName, meta) - pf, err := parquet.OpenFile(rr, int64(meta.Size)) + pf, err := parquet.OpenFile(rr, int64(meta.Size_)) if err != nil { return err } diff --git a/cmd/tempo-cli/shared.go b/cmd/tempo-cli/shared.go index e286326f3d7..092512dfa27 100644 --- a/cmd/tempo-cli/shared.go +++ b/cmd/tempo-cli/shared.go @@ -9,9 +9,8 @@ import ( "strconv" "time" - "github.com/google/uuid" - "github.com/grafana/tempo/pkg/boundedwaitgroup" + "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" ) @@ -84,7 +83,7 @@ func loadBucket(r backend.Reader, c backend.Compactor, tenantID string, windowRa if b != nil { resultsCh <- *b } - }(id, blockNum) + }(uuid.From(id), blockNum) } wg.Wait() @@ -108,14 +107,14 @@ func loadBlock(r backend.Reader, c backend.Compactor, tenantID string, id uuid.U fmt.Print(strconv.Itoa(blockNum)) } - meta, err := r.BlockMeta(context.Background(), id, tenantID) + meta, err := r.BlockMeta(context.Background(), id.UUID, tenantID) if errors.Is(err, backend.ErrDoesNotExist) && !includeCompacted { return nil, nil } else if err != nil && !errors.Is(err, backend.ErrDoesNotExist) { return nil, err } - compactedMeta, err := c.CompactedBlockMeta(id, tenantID) + compactedMeta, err := c.CompactedBlockMeta(id.UUID, tenantID) if err != nil && !errors.Is(err, backend.ErrDoesNotExist) { return nil, err } From b8ac6e62b2efc8b3664e02fc6e84b1e4d3f0deeb Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 11 Sep 2024 17:40:15 +0000 Subject: [PATCH 19/71] Lint and clean up --- tempodb/backend/block_meta.go | 132 ---------------------- tempodb/backend/tenantindex.go | 8 -- tempodb/backend/test/benchmark_test.go | 5 +- tempodb/compaction_block_selector_test.go | 1 - tempodb/encoding/vparquet2/compactor.go | 8 +- tempodb/encoding/vparquet3/compactor.go | 10 +- 6 files changed, 12 insertions(+), 152 deletions(-) diff --git a/tempodb/backend/block_meta.go b/tempodb/backend/block_meta.go index 6c5a6ee87d7..43c4dbc4513 100644 --- a/tempodb/backend/block_meta.go +++ b/tempodb/backend/block_meta.go @@ -83,77 +83,11 @@ func (s DedicatedColumnScope) ToTempopb() (tempopb.DedicatedColumn_Scope, error) } } -type compactedBlockMeta struct { - CompactedTime time.Time `json:"compactedTime"` - BlockMeta -} - -// func (b *CompactedBlockMeta) ToBackendV1Proto() (*CompactedBlockMeta, error) { -// bm, err := b.BlockMeta.ToBackendV1Proto() -// if err != nil { -// return nil, err -// } -// -// return &CompactedBlockMeta{ -// BlockMeta: *bm, -// CompactedTime: b.CompactedTime, -// }, nil -// } -// -// func (b *CompactedBlockMeta) FromBackendV1Proto(pb *CompactedBlockMeta) error { -// err := b.BlockMeta.FromBackendV1Proto(&pb.BlockMeta) -// if err != nil { -// return err -// } -// -// b.CompactedTime = pb.CompactedTime -// -// return nil -// } - const ( DefaultReplicationFactor = 0 // Replication factor for blocks from the ingester. This is the default value to indicate RF3. MetricsGeneratorReplicationFactor = 1 ) -// The BlockMeta data that is stored for each individual block. -type blockMeta struct { - // A Version that indicates the block format. This includes specifics of how the indexes and data is stored. - Version string `json:"format"` - // BlockID is a unique identifier of the block. - BlockID google_uuid.UUID `json:"blockID"` - // A TenantID that defines the tenant to which this block belongs. - TenantID string `json:"tenantID"` - // StartTime roughly matches when the first obj was written to this block. It is used to determine block. - // age for different purposes (caching, etc) - StartTime time.Time `json:"startTime"` - // EndTime roughly matches to the time the last obj was written to this block. Is currently mostly meaningless. - EndTime time.Time `json:"endTime"` - // TotalObjects counts the number of objects in this block. - TotalObjects int `json:"totalObjects"` - // The Size in bytes of the block. - Size uint64 `json:"size"` - // CompactionLevel defines the number of times this block has been compacted. - CompactionLevel uint8 `json:"compactionLevel"` - // Encoding and compression format (used only in v2) - Encoding Encoding `json:"encoding"` - // IndexPageSize holds the size of each index page in bytes (used only in v2) - IndexPageSize uint32 `json:"indexPageSize"` - // TotalRecords holds the total Records stored in the index file (used only in v2) - TotalRecords uint32 `json:"totalRecords"` - // DataEncoding is tracked by tempodb and indicates the way the bytes are encoded. - DataEncoding string `json:"dataEncoding"` - // BloomShardCount represents the number of bloom filter shards. - BloomShardCount uint16 `json:"bloomShards"` - // FooterSize contains the size of the footer in bytes (used by parquet) - FooterSize uint32 `json:"footerSize"` - // DedicatedColumns configuration for attributes (used by vParquet3) - DedicatedColumns DedicatedColumns `json:"dedicatedColumns,omitempty"` - // ReplicationFactor is the number of times the data written in this block has been replicated. - // It's left unset if replication factor is 3. Default is 0 (RF3). - ReplicationFactor uint8 `json:"replicationFactor,omitempty"` -} - // DedicatedColumn contains the configuration for a single attribute with the given name that should // be stored in a dedicated column instead of the generic attribute column. type DedicatedColumn struct { @@ -257,72 +191,6 @@ func (b *BlockMeta) DedicatedColumnsHash() uint64 { return b.DedicatedColumns.Hash() } -// func (b *BlockMeta) ToBackendV1Proto() (*BlockMeta, error) { -// blockID, err := b.BlockID.MarshalText() -// if err != nil { -// return nil, err -// } -// -// m := &BlockMeta{ -// Version: b.Version, -// BlockId: blockID, -// TenantId: b.TenantID, -// StartTime: b.StartTime, -// EndTime: b.EndTime, -// TotalObjects: int32(b.TotalObjects), -// Size_: b.Size, -// CompactionLevel: uint32(b.CompactionLevel), -// Encoding: uint32(b.Encoding), -// IndexPageSize: b.IndexPageSize, -// TotalRecords: b.TotalRecords, -// DataEncoding: b.DataEncoding, -// BloomShardCount: uint32(b.BloomShardCount), -// FooterSize: b.FooterSize, -// ReplicationFactor: uint32(b.ReplicationFactor), -// } -// -// dc, err := b.DedicatedColumns.ToTempopb() -// if err != nil { -// return nil, err -// } -// m.DedicatedColumns = dc -// -// return m, nil -// } - -// func (b *BlockMeta) FromBackendV1Proto(pb *BlockMeta) error { -// blockID, err := uuid.ParseBytes(pb.BlockId) -// if err != nil { -// return err -// } -// -// b.Version = pb.Version -// b.BlockID = blockID -// b.TenantID = pb.TenantId -// b.StartTime = pb.StartTime -// b.EndTime = pb.EndTime -// b.TotalObjects = int(pb.TotalObjects) -// b.Size = pb.Size_ -// b.CompactionLevel = uint8(pb.CompactionLevel) -// b.Encoding = Encoding(pb.Encoding) -// b.IndexPageSize = pb.IndexPageSize -// b.TotalRecords = pb.TotalRecords -// b.DataEncoding = pb.DataEncoding -// b.BloomShardCount = uint16(pb.BloomShardCount) -// b.FooterSize = pb.FooterSize -// b.ReplicationFactor = uint8(pb.ReplicationFactor) -// dcs, err := DedicatedColumnsFromTempopb(pb.DedicatedColumns) -// if err != nil { -// return err -// } -// -// if len(dcs) > 0 { -// b.DedicatedColumns = dcs -// } -// -// return nil -// } - func DedicatedColumnsFromTempopb(tempopbCols []*tempopb.DedicatedColumn) (DedicatedColumns, error) { cols := make(DedicatedColumns, 0, len(tempopbCols)) diff --git a/tempodb/backend/tenantindex.go b/tempodb/backend/tenantindex.go index 3f18da5a128..29985eb8b2b 100644 --- a/tempodb/backend/tenantindex.go +++ b/tempodb/backend/tenantindex.go @@ -15,14 +15,6 @@ const ( var _ proto.Message = &TenantIndex{} -// tenantIndex holds a list of all metas and compacted metas for a given tenant -// it is probably stored in //blockindex.json.gz as a gzipped json file -type tenantIndex struct { - CreatedAt time.Time `json:"created_at"` - Meta []*BlockMeta `json:"meta"` - CompactedMeta []*CompactedBlockMeta `json:"compacted"` -} - func newTenantIndex(meta []*BlockMeta, compactedMeta []*CompactedBlockMeta) *TenantIndex { return &TenantIndex{ CreatedAt: time.Now(), diff --git a/tempodb/backend/test/benchmark_test.go b/tempodb/backend/test/benchmark_test.go index 9b0ad5af703..d9c3a7ffa51 100644 --- a/tempodb/backend/test/benchmark_test.go +++ b/tempodb/backend/test/benchmark_test.go @@ -46,12 +46,13 @@ func BenchmarkIndexLoad(b *testing.B) { require.NoError(b, err) w := backend.NewWriter(rw) - w.WriteTenantIndex(ctx, tenant, blockMeta, nil) + err = w.WriteTenantIndex(ctx, tenant, blockMeta, nil) + require.NoError(b, err) r := backend.NewReader(rr) b.ResetTimer() for i := 0; i < b.N; i++ { - r.TenantIndex(ctx, tenant) + _, _ = r.TenantIndex(ctx, tenant) } } diff --git a/tempodb/compaction_block_selector_test.go b/tempodb/compaction_block_selector_test.go index ca8475435cf..ed14a8294cc 100644 --- a/tempodb/compaction_block_selector_test.go +++ b/tempodb/compaction_block_selector_test.go @@ -5,7 +5,6 @@ import ( "testing" "time" - google_uuid "github.com/google/uuid" "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/stretchr/testify/assert" diff --git a/tempodb/encoding/vparquet2/compactor.go b/tempodb/encoding/vparquet2/compactor.go index c0ba0237727..94462e43846 100644 --- a/tempodb/encoding/vparquet2/compactor.go +++ b/tempodb/encoding/vparquet2/compactor.go @@ -152,12 +152,12 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, newMeta := &backend.BlockMeta{ BlockID: uuid.New(), TenantID: inputs[0].TenantID, - CompactionLevel: uint32(nextCompactionLevel), - TotalObjects: int32(recordsPerBlock), // Just an estimate + CompactionLevel: nextCompactionLevel, + TotalObjects: recordsPerBlock, // Just an estimate } currentBlock = newStreamingBlock(ctx, &c.opts.BlockConfig, newMeta, r, w, tempo_io.NewBufferedWriter) - currentBlock.meta.CompactionLevel = uint32(nextCompactionLevel) + currentBlock.meta.CompactionLevel = nextCompactionLevel newCompactedBlocks = append(newCompactedBlocks, currentBlock.meta) } @@ -190,7 +190,7 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, pool.Put(lowestObject) // ship block to backend if done - if currentBlock.meta.TotalObjects >= int32(recordsPerBlock) { + if currentBlock.meta.TotalObjects >= recordsPerBlock { currentBlockPtrCopy := currentBlock currentBlockPtrCopy.meta.StartTime = minBlockStart currentBlockPtrCopy.meta.EndTime = maxBlockEnd diff --git a/tempodb/encoding/vparquet3/compactor.go b/tempodb/encoding/vparquet3/compactor.go index f0652f2871e..f169f62434c 100644 --- a/tempodb/encoding/vparquet3/compactor.go +++ b/tempodb/encoding/vparquet3/compactor.go @@ -43,7 +43,7 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, totalRecords += blockMeta.TotalObjects if blockMeta.CompactionLevel > compactionLevel { - compactionLevel = uint32(blockMeta.CompactionLevel) + compactionLevel = blockMeta.CompactionLevel } if blockMeta.StartTime.Before(minBlockStart) || minBlockStart.IsZero() { @@ -158,14 +158,14 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, newMeta := &backend.BlockMeta{ BlockID: uuid.New(), TenantID: inputs[0].TenantID, - CompactionLevel: uint32(nextCompactionLevel), - TotalObjects: int32(recordsPerBlock), // Just an estimate + CompactionLevel: nextCompactionLevel, + TotalObjects: recordsPerBlock, // Just an estimate ReplicationFactor: inputs[0].ReplicationFactor, DedicatedColumns: inputs[0].DedicatedColumns, } currentBlock = newStreamingBlock(ctx, &c.opts.BlockConfig, newMeta, r, w, tempo_io.NewBufferedWriter) - currentBlock.meta.CompactionLevel = uint32(nextCompactionLevel) + currentBlock.meta.CompactionLevel = nextCompactionLevel newCompactedBlocks = append(newCompactedBlocks, currentBlock.meta) } @@ -198,7 +198,7 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, pool.Put(lowestObject) // ship block to backend if done - if currentBlock.meta.TotalObjects >= int32(recordsPerBlock) { + if currentBlock.meta.TotalObjects >= recordsPerBlock { currentBlockPtrCopy := currentBlock currentBlockPtrCopy.meta.StartTime = minBlockStart currentBlockPtrCopy.meta.EndTime = maxBlockEnd From b780679b710be5898c1f9c1c79c1947e65109225 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 11 Sep 2024 18:07:48 +0000 Subject: [PATCH 20/71] Fix serverless --- cmd/tempo-serverless/handler.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/tempo-serverless/handler.go b/cmd/tempo-serverless/handler.go index da0b2cf8f09..0a7f0efe9ec 100644 --- a/cmd/tempo-serverless/handler.go +++ b/cmd/tempo-serverless/handler.go @@ -10,7 +10,6 @@ import ( "strings" "sync" - "github.com/google/uuid" "github.com/grafana/dskit/flagext" "github.com/grafana/dskit/user" "github.com/mitchellh/mapstructure" @@ -20,6 +19,7 @@ import ( "github.com/grafana/tempo/pkg/api" "github.com/grafana/tempo/pkg/tempopb" "github.com/grafana/tempo/pkg/traceql" + "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/backend/azure" @@ -95,7 +95,7 @@ func Handler(r *http.Request) (*tempopb.SearchResponse, *HTTPError) { TotalRecords: searchReq.TotalRecords, BlockID: blockID, DataEncoding: searchReq.DataEncoding, - Size: searchReq.Size_, + Size_: searchReq.Size_, FooterSize: searchReq.FooterSize, DedicatedColumns: dc, } From 4c7e13356a84e50caffdc834063458f7e782bdfb Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 11 Sep 2024 18:08:39 +0000 Subject: [PATCH 21/71] Fix cli --- cmd/tempo-cli/cmd-convert-parquet-3to4.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/tempo-cli/cmd-convert-parquet-3to4.go b/cmd/tempo-cli/cmd-convert-parquet-3to4.go index a76b123ef19..b0d1870597e 100644 --- a/cmd/tempo-cli/cmd-convert-parquet-3to4.go +++ b/cmd/tempo-cli/cmd-convert-parquet-3to4.go @@ -104,7 +104,7 @@ func (cmd *convertParquet3to4) Run() error { return err } - fmt.Printf("Successfully created block with size=%d and footerSize=%d\n", outMeta.Size, outMeta.FooterSize) + fmt.Printf("Successfully created block with size=%d and footerSize=%d\n", outMeta.Size_, outMeta.FooterSize) return nil } From 5594fdff096f924dfca44e08b975c710fbff59ae Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 11 Sep 2024 18:12:58 +0000 Subject: [PATCH 22/71] Fix cli --- cmd/tempo-cli/cmd-rewrite-blocks.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/tempo-cli/cmd-rewrite-blocks.go b/cmd/tempo-cli/cmd-rewrite-blocks.go index 15df12144c5..6e6c8ffb719 100644 --- a/cmd/tempo-cli/cmd-rewrite-blocks.go +++ b/cmd/tempo-cli/cmd-rewrite-blocks.go @@ -61,7 +61,7 @@ func (cmd *dropTraceCmd) Run(ctx *globalOptions) error { // print out blocks that have the trace id fmt.Println("\n\ntrace found in:") for _, block := range blocks { - fmt.Printf(" %v sz: %d traces: %d\n", block.BlockID, block.Size, block.TotalObjects) + fmt.Printf(" %v sz: %d traces: %d\n", block.BlockID, block.Size_, block.TotalObjects) } if !cmd.DropTrace { From 228ac24a312bcf2289a4caf47ee2308611b8c135 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 11 Sep 2024 19:27:30 +0000 Subject: [PATCH 23/71] Add fixture tests for roundtrip assurance between versions --- tempodb/backend/test/backend_test.go | 69 ++++++++++++++++++ tempodb/backend/test/benchmark_test.go | 8 +- .../test-data/benchmark-tenant/index.json.gz | Bin 0 -> 34019 bytes .../meta.json | 1 + .../meta.json | 1 + .../meta.json | 1 + .../meta.json | 1 + .../meta.json | 1 + .../meta.json | 1 + .../test-data/single-tenant/index.json.gz | Bin 0 -> 439 bytes 10 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 tempodb/backend/test/backend_test.go create mode 100644 tempodb/backend/test/test-data/benchmark-tenant/index.json.gz create mode 100644 tempodb/backend/test/test-data/single-tenant/25693787-ef3d-4257-a98b-7b178a27fd41/meta.json create mode 100644 tempodb/backend/test/test-data/single-tenant/520fbe53-3995-4bf7-b9a6-00147cd1dbc6/meta.json create mode 100644 tempodb/backend/test/test-data/single-tenant/9fa7d4e7-caf3-4632-b3ce-1704d4f7b8e6/meta.json create mode 100644 tempodb/backend/test/test-data/single-tenant/be5e9b8b-a364-4351-9b25-a8a2386a13d5/meta.json create mode 100644 tempodb/backend/test/test-data/single-tenant/bf0038bd-9dcc-4385-b499-d757c305ac0f/meta.json create mode 100644 tempodb/backend/test/test-data/single-tenant/f3231fec-3880-4f97-8358-48a705767c10/meta.json create mode 100644 tempodb/backend/test/test-data/single-tenant/index.json.gz diff --git a/tempodb/backend/test/backend_test.go b/tempodb/backend/test/backend_test.go new file mode 100644 index 00000000000..35aef499281 --- /dev/null +++ b/tempodb/backend/test/backend_test.go @@ -0,0 +1,69 @@ +package test + +import ( + "context" + "testing" + + "github.com/grafana/tempo/tempodb/backend" + "github.com/grafana/tempo/tempodb/backend/local" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestFixtures(t *testing.T) { + var ( + tenant = "single-tenant" + ctx = context.Background() + ) + + // Create the fixtures, but commit them. + // metas := []*backend.BlockMeta{ + // backend.NewBlockMeta(tenant, uuid.New().UUID, "v1", backend.EncGZIP, "adsf"), + // backend.NewBlockMeta(tenant, uuid.New().UUID, "v2", backend.EncNone, "adsf"), + // backend.NewBlockMeta(tenant, uuid.New().UUID, "v3", backend.EncLZ4_4M, "adsf"), + // } + + rr, rw, _, err := local.New(&local.Config{ + Path: "./test-data", + }) + require.NoError(t, err) + + var ( + _ = backend.NewWriter(rw) + r = backend.NewReader(rr) + ) + + _, err = r.TenantIndex(ctx, tenant) + assert.NoError(t, err) + + // for _, meta := range metas { + // err = w.WriteBlockMeta(ctx, meta) + // require.NoError(t, err) + // } + + metas, compactedMetas, err := rr.ListBlocks(ctx, tenant) + require.NoError(t, err) + require.Len(t, compactedMetas, 0) + + blockMetas := make([]*backend.BlockMeta, 0, len(metas)) + for _, u := range metas { + meta, e := r.BlockMeta(ctx, u, tenant) + require.NoError(t, e) + blockMetas = append(blockMetas, meta) + } + + // err = backend.NewWriter(rw).WriteTenantIndex(ctx, tenant, blockMetas, nil) + // require.NoError(t, err) + + // for _, meta := range metas { + // m, e := r.BlockMeta(ctx, meta.BlockID.UUID, tenant) + // require.NoError(t, e) + // require.Equal(t, meta, m) + // } + + var i *backend.TenantIndex + i, err = r.TenantIndex(ctx, tenant) + require.NoError(t, err) + require.Equal(t, blockMetas, i.Meta) + require.Len(t, i.Meta, len(metas)) +} diff --git a/tempodb/backend/test/benchmark_test.go b/tempodb/backend/test/benchmark_test.go index d9c3a7ffa51..93f2bc08f58 100644 --- a/tempodb/backend/test/benchmark_test.go +++ b/tempodb/backend/test/benchmark_test.go @@ -12,8 +12,10 @@ import ( ) func BenchmarkIndexLoad(b *testing.B) { - ctx := context.Background() - tenant := "test" + var ( + tenant = "benchmark-tenant" + ctx = context.Background() + ) blockMeta := make([]*backend.BlockMeta, 1000) for i := range len(blockMeta) { @@ -41,7 +43,7 @@ func BenchmarkIndexLoad(b *testing.B) { } rr, rw, _, err := local.New(&local.Config{ - Path: "/home/zach/go/src/github.com/grafana/tempo/tempodb/backend/testdata", + Path: "./test-data", }) require.NoError(b, err) diff --git a/tempodb/backend/test/test-data/benchmark-tenant/index.json.gz b/tempodb/backend/test/test-data/benchmark-tenant/index.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..bc0f1d0588f175a4178a31f1684485ca06b99379 GIT binary patch literal 34019 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 huvgBHK5KP*xc=(t`tbA(009600{|>6 Date: Wed, 11 Sep 2024 19:28:55 +0000 Subject: [PATCH 24/71] Clean up notes from proto definition --- tempodb/backend/v1.pb.go | 45 +++++++++++++++++-------------------- tempodb/backend/v1/v1.proto | 9 -------- 2 files changed, 20 insertions(+), 34 deletions(-) diff --git a/tempodb/backend/v1.pb.go b/tempodb/backend/v1.pb.go index d634572c521..45f53e749f1 100644 --- a/tempodb/backend/v1.pb.go +++ b/tempodb/backend/v1.pb.go @@ -5,16 +5,15 @@ package backend import ( fmt "fmt" - io "io" - math "math" - math_bits "math/bits" - time "time" - _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" github_com_grafana_tempo_pkg_uuid "github.com/grafana/tempo/pkg/uuid" _ "google.golang.org/protobuf/types/known/timestamppb" + io "io" + math "math" + math_bits "math/bits" + time "time" ) // Reference imports to suppress errors if they are not otherwise used. @@ -30,26 +29,22 @@ var _ = time.Kitchen const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type BlockMeta struct { - Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"format"` - BlockID github_com_grafana_tempo_pkg_uuid.UUID `protobuf:"bytes,2,opt,name=block_id,json=blockId,proto3,customtype=github.com/grafana/tempo/pkg/uuid.UUID" json:"blockID"` - TenantID string `protobuf:"bytes,5,opt,name=tenant_id,json=tenantId,proto3" json:"tenantID"` - StartTime time.Time `protobuf:"bytes,6,opt,name=start_time,json=startTime,proto3,stdtime" json:"startTime"` - EndTime time.Time `protobuf:"bytes,7,opt,name=end_time,json=endTime,proto3,stdtime" json:"endTime"` - TotalObjects int32 `protobuf:"varint,8,opt,name=total_objects,json=totalObjects,proto3" json:"totalObjects"` - Size_ uint64 `protobuf:"varint,9,opt,name=size,proto3" json:"size,omitempty"` - CompactionLevel uint32 `protobuf:"varint,10,opt,name=compaction_level,json=compactionLevel,proto3" json:"compactionLevel"` - Encoding Encoding `protobuf:"bytes,11,opt,name=encoding,proto3,customtype=Encoding" json:"encoding"` - IndexPageSize uint32 `protobuf:"varint,12,opt,name=index_page_size,json=indexPageSize,proto3" json:"indexPageSize"` - TotalRecords uint32 `protobuf:"varint,13,opt,name=total_records,json=totalRecords,proto3" json:"totalRecords"` - DataEncoding string `protobuf:"bytes,14,opt,name=data_encoding,json=dataEncoding,proto3" json:"dataEncoding"` - BloomShardCount uint32 `protobuf:"varint,15,opt,name=bloom_shard_count,json=bloomShardCount,proto3" json:"bloomShards"` - FooterSize uint32 `protobuf:"varint,16,opt,name=footer_size,json=footerSize,proto3" json:"footerSize"` - // repeated bytes dedicated_columns = 17 [(gogoproto.customtype) = "github.com/grafana/tempo/pkg/tempopb.DedicatedColumn"]; - // repeated bytes dedicated_columns = 17 [(gogoproto.customtype) = "github.com/grafana/tempo/tempodb/backend/meta.DedicatedColumn"]; - DedicatedColumns DedicatedColumns `protobuf:"bytes,17,opt,name=dedicated_columns,json=dedicatedColumns,proto3,customtype=DedicatedColumns" json:"dedicatedColumns,omitempty"` - // bytes dedicated_columns = 17; - // repeated tempopb.DedicatedColumn dedicated_columns = 17[(gogoproto.jsontag) = "dedicatedColumns,omitempty"]; - ReplicationFactor uint32 `protobuf:"varint,18,opt,name=replication_factor,json=replicationFactor,proto3" json:"replicationFactor,omitempty"` + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"format"` + BlockID github_com_grafana_tempo_pkg_uuid.UUID `protobuf:"bytes,2,opt,name=block_id,json=blockId,proto3,customtype=github.com/grafana/tempo/pkg/uuid.UUID" json:"blockID"` + TenantID string `protobuf:"bytes,5,opt,name=tenant_id,json=tenantId,proto3" json:"tenantID"` + StartTime time.Time `protobuf:"bytes,6,opt,name=start_time,json=startTime,proto3,stdtime" json:"startTime"` + EndTime time.Time `protobuf:"bytes,7,opt,name=end_time,json=endTime,proto3,stdtime" json:"endTime"` + TotalObjects int32 `protobuf:"varint,8,opt,name=total_objects,json=totalObjects,proto3" json:"totalObjects"` + Size_ uint64 `protobuf:"varint,9,opt,name=size,proto3" json:"size,omitempty"` + CompactionLevel uint32 `protobuf:"varint,10,opt,name=compaction_level,json=compactionLevel,proto3" json:"compactionLevel"` + Encoding Encoding `protobuf:"bytes,11,opt,name=encoding,proto3,customtype=Encoding" json:"encoding"` + IndexPageSize uint32 `protobuf:"varint,12,opt,name=index_page_size,json=indexPageSize,proto3" json:"indexPageSize"` + TotalRecords uint32 `protobuf:"varint,13,opt,name=total_records,json=totalRecords,proto3" json:"totalRecords"` + DataEncoding string `protobuf:"bytes,14,opt,name=data_encoding,json=dataEncoding,proto3" json:"dataEncoding"` + BloomShardCount uint32 `protobuf:"varint,15,opt,name=bloom_shard_count,json=bloomShardCount,proto3" json:"bloomShards"` + FooterSize uint32 `protobuf:"varint,16,opt,name=footer_size,json=footerSize,proto3" json:"footerSize"` + DedicatedColumns DedicatedColumns `protobuf:"bytes,17,opt,name=dedicated_columns,json=dedicatedColumns,proto3,customtype=DedicatedColumns" json:"dedicatedColumns,omitempty"` + ReplicationFactor uint32 `protobuf:"varint,18,opt,name=replication_factor,json=replicationFactor,proto3" json:"replicationFactor,omitempty"` } func (m *BlockMeta) Reset() { *m = BlockMeta{} } diff --git a/tempodb/backend/v1/v1.proto b/tempodb/backend/v1/v1.proto index f4be7add048..80747906735 100644 --- a/tempodb/backend/v1/v1.proto +++ b/tempodb/backend/v1/v1.proto @@ -2,16 +2,11 @@ syntax = "proto3"; package backend.v1; -// import "pkg/tempopb/tempo.proto"; - import "google/protobuf/timestamp.proto"; import "github.com/gogo/protobuf/gogoproto/gogo.proto"; -// option go_package = "github.com/grafana/tempo/tempodb/backend/v1"; option go_package = "tempodb/backend"; -option (gogoproto.marshaler_all) = true; - message BlockMeta { string version = 1[(gogoproto.jsontag) = "format"]; bytes block_id = 2[(gogoproto.jsontag) = "blockID", (gogoproto.customname) = "BlockID", (gogoproto.customtype) = "github.com/grafana/tempo/pkg/uuid.UUID", (gogoproto.nullable) = false]; @@ -27,11 +22,7 @@ message BlockMeta { string data_encoding = 14[(gogoproto.jsontag) = "dataEncoding"]; uint32 bloom_shard_count = 15[(gogoproto.jsontag) = "bloomShards"]; uint32 footer_size = 16[(gogoproto.jsontag) = "footerSize"]; - // repeated bytes dedicated_columns = 17 [(gogoproto.customtype) = "github.com/grafana/tempo/pkg/tempopb.DedicatedColumn"]; - // repeated bytes dedicated_columns = 17 [(gogoproto.customtype) = "github.com/grafana/tempo/tempodb/backend/meta.DedicatedColumn"]; bytes dedicated_columns = 17 [(gogoproto.customtype) = "DedicatedColumns", (gogoproto.jsontag) = "dedicatedColumns,omitempty", (gogoproto.nullable) = false]; - // bytes dedicated_columns = 17; - // repeated tempopb.DedicatedColumn dedicated_columns = 17[(gogoproto.jsontag) = "dedicatedColumns,omitempty"]; uint32 replication_factor = 18[(gogoproto.jsontag) = "replicationFactor,omitempty"]; } From dfaea73cd892e07af945dd44746a0196006f33fb Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 11 Sep 2024 22:00:50 +0000 Subject: [PATCH 25/71] Update backend/test --- tempodb/backend/test/backend_test.go | 34 +++++++++++++----- .../meta.json | 2 +- .../meta.json | 1 - .../meta.json | 2 +- .../meta.json | 1 - .../meta.json | 1 + .../meta.json | 1 - .../meta.json | 2 +- .../test-data/single-tenant/index.json.gz | Bin 439 -> 378 bytes 9 files changed, 30 insertions(+), 14 deletions(-) rename tempodb/backend/test/test-data/single-tenant/{bf0038bd-9dcc-4385-b499-d757c305ac0f => 05d4e1b5-bed7-42fe-a392-ca807fdb0214}/meta.json (78%) delete mode 100644 tempodb/backend/test/test-data/single-tenant/520fbe53-3995-4bf7-b9a6-00147cd1dbc6/meta.json rename tempodb/backend/test/test-data/single-tenant/{25693787-ef3d-4257-a98b-7b178a27fd41 => 522761e6-6dd1-42b5-833a-d3b07437d4b6}/meta.json (78%) delete mode 100644 tempodb/backend/test/test-data/single-tenant/9fa7d4e7-caf3-4632-b3ce-1704d4f7b8e6/meta.json create mode 100644 tempodb/backend/test/test-data/single-tenant/b8c6a82a-2f45-487b-a84f-20ca23faaa6a/meta.json delete mode 100644 tempodb/backend/test/test-data/single-tenant/be5e9b8b-a364-4351-9b25-a8a2386a13d5/meta.json rename tempodb/backend/test/test-data/single-tenant/{f3231fec-3880-4f97-8358-48a705767c10 => beafbedc-0dc6-4aa1-b404-3d4e00e08613}/meta.json (78%) diff --git a/tempodb/backend/test/backend_test.go b/tempodb/backend/test/backend_test.go index 35aef499281..e2b3707b0f7 100644 --- a/tempodb/backend/test/backend_test.go +++ b/tempodb/backend/test/backend_test.go @@ -19,8 +19,9 @@ func TestFixtures(t *testing.T) { // Create the fixtures, but commit them. // metas := []*backend.BlockMeta{ // backend.NewBlockMeta(tenant, uuid.New().UUID, "v1", backend.EncGZIP, "adsf"), - // backend.NewBlockMeta(tenant, uuid.New().UUID, "v2", backend.EncNone, "adsf"), + // backend.NewBlockMeta(tenant, uuid.New().UUID, "v2", backend.EncNone, "adsf"), // backend.NewBlockMeta(tenant, uuid.New().UUID, "v3", backend.EncLZ4_4M, "adsf"), + // backend.NewBlockMeta(tenant, uuid.New().UUID, "v4", backend.EncLZ4_1M, "adsf"), // } rr, rw, _, err := local.New(&local.Config{ @@ -41,19 +42,27 @@ func TestFixtures(t *testing.T) { // require.NoError(t, err) // } - metas, compactedMetas, err := rr.ListBlocks(ctx, tenant) + listMetas, listCompactedMetas, err := rr.ListBlocks(ctx, tenant) require.NoError(t, err) - require.Len(t, compactedMetas, 0) + require.Len(t, listCompactedMetas, 0) - blockMetas := make([]*backend.BlockMeta, 0, len(metas)) - for _, u := range metas { + for _, v := range listMetas { + t.Logf("listMetas: %v", v) + } + + blockMetas := make([]*backend.BlockMeta, 0, len(listMetas)) + for _, u := range listMetas { meta, e := r.BlockMeta(ctx, u, tenant) require.NoError(t, e) blockMetas = append(blockMetas, meta) + require.Equal(t, tenant, meta.TenantID) + t.Logf("meta: %v", meta) } - // err = backend.NewWriter(rw).WriteTenantIndex(ctx, tenant, blockMetas, nil) - // require.NoError(t, err) + nonZeroMeta(t, blockMetas) + + err = backend.NewWriter(rw).WriteTenantIndex(ctx, tenant, blockMetas, nil) + require.NoError(t, err) // for _, meta := range metas { // m, e := r.BlockMeta(ctx, meta.BlockID.UUID, tenant) @@ -65,5 +74,14 @@ func TestFixtures(t *testing.T) { i, err = r.TenantIndex(ctx, tenant) require.NoError(t, err) require.Equal(t, blockMetas, i.Meta) - require.Len(t, i.Meta, len(metas)) + require.Len(t, i.Meta, len(listMetas)) +} + +func nonZeroMeta(t *testing.T, m []*backend.BlockMeta) { + for _, v := range m { + assert.NotZero(t, v.BlockID, "blockid is zero, id: %v", v.BlockID) + assert.NotZero(t, v.BlockID, "blockid is zero, id: %v", v.BlockID) + assert.NotZero(t, v.BlockID, "blockid is zero, id: %v", v.BlockID) + assert.NotZero(t, v.BlockID, "blockid is zero, id: %v", v.BlockID) + } } diff --git a/tempodb/backend/test/test-data/single-tenant/bf0038bd-9dcc-4385-b499-d757c305ac0f/meta.json b/tempodb/backend/test/test-data/single-tenant/05d4e1b5-bed7-42fe-a392-ca807fdb0214/meta.json similarity index 78% rename from tempodb/backend/test/test-data/single-tenant/bf0038bd-9dcc-4385-b499-d757c305ac0f/meta.json rename to tempodb/backend/test/test-data/single-tenant/05d4e1b5-bed7-42fe-a392-ca807fdb0214/meta.json index e6ffa9999f6..c99c183c737 100644 --- a/tempodb/backend/test/test-data/single-tenant/bf0038bd-9dcc-4385-b499-d757c305ac0f/meta.json +++ b/tempodb/backend/test/test-data/single-tenant/05d4e1b5-bed7-42fe-a392-ca807fdb0214/meta.json @@ -1 +1 @@ -{"format":"v1","blockID":"bf0038bd-9dcc-4385-b499-d757c305ac0f","tenantID":"single-tenant","startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z","totalObjects":0,"compactionLevel":0,"encoding":"gzip","indexPageSize":0,"totalRecords":0,"dataEncoding":"adsf","bloomShards":0,"footerSize":0} \ No newline at end of file +{"format":"v1","blockID":"05d4e1b5-bed7-42fe-a392-ca807fdb0214","tenantID":"single-tenant","startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z","totalObjects":0,"compactionLevel":0,"encoding":"gzip","indexPageSize":0,"totalRecords":0,"dataEncoding":"adsf","bloomShards":0,"footerSize":0} \ No newline at end of file diff --git a/tempodb/backend/test/test-data/single-tenant/520fbe53-3995-4bf7-b9a6-00147cd1dbc6/meta.json b/tempodb/backend/test/test-data/single-tenant/520fbe53-3995-4bf7-b9a6-00147cd1dbc6/meta.json deleted file mode 100644 index f5b4f8757e1..00000000000 --- a/tempodb/backend/test/test-data/single-tenant/520fbe53-3995-4bf7-b9a6-00147cd1dbc6/meta.json +++ /dev/null @@ -1 +0,0 @@ -{"format":"v3","blockID":"520fbe53-3995-4bf7-b9a6-00147cd1dbc6","tenantID":"single-tenant","startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z","totalObjects":0,"compactionLevel":0,"encoding":"lz4","indexPageSize":0,"totalRecords":0,"dataEncoding":"adsf","bloomShards":0,"footerSize":0} \ No newline at end of file diff --git a/tempodb/backend/test/test-data/single-tenant/25693787-ef3d-4257-a98b-7b178a27fd41/meta.json b/tempodb/backend/test/test-data/single-tenant/522761e6-6dd1-42b5-833a-d3b07437d4b6/meta.json similarity index 78% rename from tempodb/backend/test/test-data/single-tenant/25693787-ef3d-4257-a98b-7b178a27fd41/meta.json rename to tempodb/backend/test/test-data/single-tenant/522761e6-6dd1-42b5-833a-d3b07437d4b6/meta.json index 843716aae18..76e805a6b9a 100644 --- a/tempodb/backend/test/test-data/single-tenant/25693787-ef3d-4257-a98b-7b178a27fd41/meta.json +++ b/tempodb/backend/test/test-data/single-tenant/522761e6-6dd1-42b5-833a-d3b07437d4b6/meta.json @@ -1 +1 @@ -{"format":"v2","blockID":"25693787-ef3d-4257-a98b-7b178a27fd41","tenantID":"single-tenant","startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z","totalObjects":0,"compactionLevel":0,"encoding":"none","indexPageSize":0,"totalRecords":0,"dataEncoding":"adsf","bloomShards":0,"footerSize":0} \ No newline at end of file +{"format":"v2","blockID":"522761e6-6dd1-42b5-833a-d3b07437d4b6","tenantID":"single-tenant","startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z","totalObjects":0,"compactionLevel":0,"encoding":"none","indexPageSize":0,"totalRecords":0,"dataEncoding":"adsf","bloomShards":0,"footerSize":0} \ No newline at end of file diff --git a/tempodb/backend/test/test-data/single-tenant/9fa7d4e7-caf3-4632-b3ce-1704d4f7b8e6/meta.json b/tempodb/backend/test/test-data/single-tenant/9fa7d4e7-caf3-4632-b3ce-1704d4f7b8e6/meta.json deleted file mode 100644 index 4efea83cd96..00000000000 --- a/tempodb/backend/test/test-data/single-tenant/9fa7d4e7-caf3-4632-b3ce-1704d4f7b8e6/meta.json +++ /dev/null @@ -1 +0,0 @@ -{"format":"v2","blockID":"9fa7d4e7-caf3-4632-b3ce-1704d4f7b8e6","tenantID":"single-tenant","startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z","totalObjects":0,"compactionLevel":0,"encoding":"none","indexPageSize":0,"totalRecords":0,"dataEncoding":"adsf","bloomShards":0,"footerSize":0} \ No newline at end of file diff --git a/tempodb/backend/test/test-data/single-tenant/b8c6a82a-2f45-487b-a84f-20ca23faaa6a/meta.json b/tempodb/backend/test/test-data/single-tenant/b8c6a82a-2f45-487b-a84f-20ca23faaa6a/meta.json new file mode 100644 index 00000000000..aa3a30171d2 --- /dev/null +++ b/tempodb/backend/test/test-data/single-tenant/b8c6a82a-2f45-487b-a84f-20ca23faaa6a/meta.json @@ -0,0 +1 @@ +{"format":"v4","blockID":"b8c6a82a-2f45-487b-a84f-20ca23faaa6a","tenantID":"single-tenant","startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z","totalObjects":0,"compactionLevel":0,"encoding":"lz4-1M","indexPageSize":0,"totalRecords":0,"dataEncoding":"adsf","bloomShards":0,"footerSize":0} \ No newline at end of file diff --git a/tempodb/backend/test/test-data/single-tenant/be5e9b8b-a364-4351-9b25-a8a2386a13d5/meta.json b/tempodb/backend/test/test-data/single-tenant/be5e9b8b-a364-4351-9b25-a8a2386a13d5/meta.json deleted file mode 100644 index 32e985a1db3..00000000000 --- a/tempodb/backend/test/test-data/single-tenant/be5e9b8b-a364-4351-9b25-a8a2386a13d5/meta.json +++ /dev/null @@ -1 +0,0 @@ -{"format":"v1","blockID":"be5e9b8b-a364-4351-9b25-a8a2386a13d5","tenantID":"single-tenant","startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z","totalObjects":0,"compactionLevel":0,"encoding":"gzip","indexPageSize":0,"totalRecords":0,"dataEncoding":"adsf","bloomShards":0,"footerSize":0} \ No newline at end of file diff --git a/tempodb/backend/test/test-data/single-tenant/f3231fec-3880-4f97-8358-48a705767c10/meta.json b/tempodb/backend/test/test-data/single-tenant/beafbedc-0dc6-4aa1-b404-3d4e00e08613/meta.json similarity index 78% rename from tempodb/backend/test/test-data/single-tenant/f3231fec-3880-4f97-8358-48a705767c10/meta.json rename to tempodb/backend/test/test-data/single-tenant/beafbedc-0dc6-4aa1-b404-3d4e00e08613/meta.json index 1f37e51194a..2834273a8fd 100644 --- a/tempodb/backend/test/test-data/single-tenant/f3231fec-3880-4f97-8358-48a705767c10/meta.json +++ b/tempodb/backend/test/test-data/single-tenant/beafbedc-0dc6-4aa1-b404-3d4e00e08613/meta.json @@ -1 +1 @@ -{"format":"v3","blockID":"f3231fec-3880-4f97-8358-48a705767c10","tenantID":"single-tenant","startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z","totalObjects":0,"compactionLevel":0,"encoding":"lz4","indexPageSize":0,"totalRecords":0,"dataEncoding":"adsf","bloomShards":0,"footerSize":0} \ No newline at end of file +{"format":"v3","blockID":"beafbedc-0dc6-4aa1-b404-3d4e00e08613","tenantID":"single-tenant","startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z","totalObjects":0,"compactionLevel":0,"encoding":"lz4","indexPageSize":0,"totalRecords":0,"dataEncoding":"adsf","bloomShards":0,"footerSize":0} \ No newline at end of file diff --git a/tempodb/backend/test/test-data/single-tenant/index.json.gz b/tempodb/backend/test/test-data/single-tenant/index.json.gz index 0cc74fe8c4c837072ab22688a1ee1c98ba0c6996..150c6be17d290b7399b5d6cc5ebe2ef5237a36e7 100644 GIT binary patch delta 366 zcmV-!0g?W<1Ns7x6@Sdo&x#Z=5C-sfsdJZ9lIp)_JqU{8?nx1;B$ctXJ6U?dBD3tf z%l0Tb7jG^Dbt>xnNPZ6xHkGRJi&U7vl4Yb3jk&dEYR8HBg|jsFBahujXkgVUFnxM} zRJL`G+#6`XFC~0`{SqdiHnJMuqSx3X+oULNv>0TdK1EN~Fn=^qHA}90;yCBSqIljw z1IH>`y`5KmY9lhZ&n?lk&(kY3$A2HxQe}DPziFsPn5cnJ);kGxF8Ph#>$2}OhZ5&} zfC&z#`3@SGbJQR2<)An7N%xz*=!1r`#dA@VDzE+oB_7lH|7E@TD!;E%DOI;$EsxFL zT=s&iwYKk!c4yedXppUMad1vBI!`^jKCl+ukfr=t&|Bx->-1T2KfRa@(F z_@44K{ECY%aDO?YY7$3CF*>xVdQ6c=R7zW)i!LdTw})$YvR9&YS*}>w7b_k!S3*0I z!9-b5du5BQJ_Wf!T30NWzQC2lNlYOj(`eC>(-@O+$bk)oku?=}d$_iz`Tk1n`VCiA zib5(FOU`I1I7~K1EZ+G{%5hfppT>20x+)pcRWect3MFlg9s{|6Hn3ODk3MU4d$|7U W>H6^W4FCZD{{sLlEab0G2LJ%Bb Date: Wed, 11 Sep 2024 22:01:11 +0000 Subject: [PATCH 26/71] Be more specific about unmarshal UUID --- pkg/uuid/uuid.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pkg/uuid/uuid.go b/pkg/uuid/uuid.go index 5f2c594e423..90c8d402af5 100644 --- a/pkg/uuid/uuid.go +++ b/pkg/uuid/uuid.go @@ -70,8 +70,13 @@ func (u UUID) MarshalJSON() ([]byte, error) { } func (u *UUID) UnmarshalJSON(data []byte) error { - uu := google_uuid.UUID{} - err := json.Unmarshal(data, &uu) + var s string + err := json.Unmarshal(data, &s) + if err != nil { + return err + } + + uu, err := google_uuid.Parse(s) if err != nil { return err } From 5232218bb3a165eee40490a6e9c90f431e1b2edf Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 11 Sep 2024 22:03:59 +0000 Subject: [PATCH 27/71] Include event for compacted block --- tempodb/encoding/vparquet4/compactor.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tempodb/encoding/vparquet4/compactor.go b/tempodb/encoding/vparquet4/compactor.go index 52005669e5a..10f342311a9 100644 --- a/tempodb/encoding/vparquet4/compactor.go +++ b/tempodb/encoding/vparquet4/compactor.go @@ -13,6 +13,7 @@ import ( "github.com/go-kit/log/level" tempoUtil "github.com/grafana/tempo/pkg/util" "github.com/parquet-go/parquet-go" + "go.opentelemetry.io/otel/attribute" tempo_io "github.com/grafana/tempo/pkg/io" "github.com/grafana/tempo/pkg/uuid" @@ -261,6 +262,12 @@ func (c *Compactor) finishBlock(ctx context.Context, block *streamingBlock, l lo } level.Info(l).Log("msg", "wrote compacted block", "meta", fmt.Sprintf("%+v", block.meta)) + + span.AddEvent("wrote compacted block") + span.SetAttributes( + attribute.String("blockID", block.meta.BlockID.String()), + ) + compactionLevel := int(block.meta.CompactionLevel) - 1 if c.opts.BytesWritten != nil { c.opts.BytesWritten(compactionLevel, bytesFlushed) From 5eecd3cbad1e330364517849bf0ab1ffef0350da Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Thu, 12 Sep 2024 13:28:21 +0000 Subject: [PATCH 28/71] Use better json tag for compacted meta --- tempodb/backend/v1.pb.go | 104 ++++++++++++++++++------------------ tempodb/backend/v1/v1.proto | 2 +- 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/tempodb/backend/v1.pb.go b/tempodb/backend/v1.pb.go index 45f53e749f1..1f0ee337b2d 100644 --- a/tempodb/backend/v1.pb.go +++ b/tempodb/backend/v1.pb.go @@ -173,7 +173,7 @@ func (m *BlockMeta) GetReplicationFactor() uint32 { type CompactedBlockMeta struct { BlockMeta `protobuf:"bytes,1,opt,name=block_meta,json=blockMeta,proto3,embedded=block_meta" json:"block_meta"` - CompactedTime time.Time `protobuf:"bytes,2,opt,name=compacted_time,json=compactedTime,proto3,stdtime" json:"compacted_time"` + CompactedTime time.Time `protobuf:"bytes,2,opt,name=compacted_time,json=compactedTime,proto3,stdtime" json:"compactedTime"` } func (m *CompactedBlockMeta) Reset() { *m = CompactedBlockMeta{} } @@ -285,57 +285,57 @@ func init() { func init() { proto.RegisterFile("tempodb/backend/v1/v1.proto", fileDescriptor_6bc10ae735c1a340) } var fileDescriptor_6bc10ae735c1a340 = []byte{ - // 785 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0x4f, 0x6b, 0xeb, 0x46, - 0x10, 0xb7, 0xf2, 0xf2, 0x62, 0x7b, 0x1d, 0xc7, 0xf6, 0x3e, 0x1e, 0x08, 0x3f, 0xf0, 0x9a, 0x50, - 0x8a, 0x1f, 0xbc, 0x4a, 0x24, 0x25, 0x85, 0x52, 0x08, 0xd4, 0x76, 0x0a, 0xe9, 0xdf, 0xa0, 0x24, - 0x97, 0x5e, 0xc4, 0x4a, 0xbb, 0x56, 0xd4, 0x48, 0x5a, 0x23, 0xad, 0x4d, 0x9b, 0x4f, 0x91, 0xaf, - 0xd0, 0xef, 0xd2, 0x43, 0x8e, 0x39, 0x96, 0x1e, 0xd4, 0xe2, 0xdc, 0x44, 0x3f, 0x44, 0xd9, 0x91, - 0x6c, 0xd9, 0x0e, 0x25, 0xef, 0x36, 0x33, 0xbf, 0xf9, 0xcd, 0xcc, 0x6f, 0xb4, 0x23, 0xf4, 0x4e, - 0xf2, 0x70, 0x2a, 0x98, 0x63, 0x3a, 0xd4, 0xbd, 0xe5, 0x11, 0x33, 0xe7, 0x47, 0xe6, 0xfc, 0xc8, - 0x98, 0xc6, 0x42, 0x0a, 0x8c, 0x8a, 0xa0, 0x31, 0x3f, 0xea, 0x12, 0x4f, 0x08, 0x2f, 0xe0, 0x26, - 0x20, 0xce, 0x6c, 0x62, 0x4a, 0x3f, 0xe4, 0x89, 0xa4, 0xe1, 0x34, 0x4f, 0xee, 0x7e, 0xe6, 0xf9, - 0xf2, 0x66, 0xe6, 0x18, 0xae, 0x08, 0x4d, 0x4f, 0x78, 0xa2, 0xcc, 0x54, 0x1e, 0x38, 0x60, 0xe5, - 0xe9, 0x87, 0xff, 0x56, 0x51, 0x7d, 0x18, 0x08, 0xf7, 0xf6, 0x07, 0x2e, 0x29, 0xfe, 0x04, 0x55, - 0xe7, 0x3c, 0x4e, 0x7c, 0x11, 0xe9, 0x5a, 0x5f, 0x1b, 0xd4, 0x87, 0x28, 0x4b, 0xc9, 0xde, 0x44, - 0xc4, 0x21, 0x95, 0xd6, 0x12, 0xc2, 0x36, 0xaa, 0x39, 0x8a, 0x62, 0xfb, 0x4c, 0xdf, 0xe9, 0x6b, - 0x83, 0xfd, 0xe1, 0xf8, 0x21, 0x25, 0x95, 0xbf, 0x52, 0xf2, 0xe9, 0x7a, 0xf3, 0x98, 0x4e, 0x68, - 0x44, 0x4d, 0x50, 0x66, 0x4e, 0x6f, 0x3d, 0x73, 0x36, 0xf3, 0x99, 0x71, 0x7d, 0x7d, 0x3e, 0x5e, - 0xa4, 0xa4, 0x0a, 0x4d, 0xcf, 0xc7, 0x59, 0x4a, 0xaa, 0x4e, 0x6e, 0x5a, 0x85, 0xc1, 0xf0, 0x09, - 0xaa, 0x4b, 0x1e, 0xd1, 0x48, 0xaa, 0x0e, 0xaf, 0x61, 0x10, 0x7d, 0x91, 0x92, 0xda, 0x15, 0x04, - 0x81, 0x54, 0x93, 0x85, 0x6d, 0x2d, 0x2d, 0x86, 0x2f, 0x10, 0x4a, 0x24, 0x8d, 0xa5, 0xad, 0x76, - 0xa2, 0xef, 0xf5, 0xb5, 0x41, 0xe3, 0xb8, 0x6b, 0xe4, 0x0b, 0x33, 0x96, 0x6b, 0x30, 0xae, 0x96, - 0x0b, 0x1b, 0xbe, 0x55, 0x53, 0x67, 0x29, 0xa9, 0x03, 0x4b, 0xc5, 0xef, 0xff, 0x26, 0x9a, 0x55, - 0xba, 0xf8, 0x5b, 0x54, 0xe3, 0x11, 0xcb, 0xeb, 0x55, 0x5f, 0xac, 0xf7, 0xa6, 0xa8, 0x57, 0xe5, - 0x11, 0x5b, 0x55, 0x5b, 0x3a, 0xf8, 0x04, 0x35, 0xa5, 0x90, 0x34, 0xb0, 0x85, 0xf3, 0x0b, 0x77, - 0x65, 0xa2, 0xd7, 0xfa, 0xda, 0xe0, 0xf5, 0xb0, 0x9d, 0xa5, 0x64, 0x1f, 0x80, 0x9f, 0xf2, 0xb8, - 0xb5, 0xe1, 0x61, 0x8c, 0x76, 0x13, 0xff, 0x8e, 0xeb, 0xf5, 0xbe, 0x36, 0xd8, 0xb5, 0xc0, 0xc6, - 0xa7, 0xa8, 0xed, 0x8a, 0x70, 0x4a, 0x5d, 0xe9, 0x8b, 0xc8, 0x0e, 0xf8, 0x9c, 0x07, 0x3a, 0xea, - 0x6b, 0x83, 0xe6, 0xf0, 0x4d, 0x96, 0x92, 0x56, 0x89, 0x7d, 0xaf, 0x20, 0x6b, 0x3b, 0x80, 0x3f, - 0x28, 0x59, 0xae, 0x60, 0x7e, 0xe4, 0xe9, 0x0d, 0xf8, 0x80, 0xed, 0xe2, 0x03, 0xd6, 0xce, 0x8a, - 0xb8, 0xb5, 0xca, 0xc0, 0x5f, 0xa2, 0x96, 0x1f, 0x31, 0xfe, 0xab, 0x3d, 0xa5, 0x1e, 0xb7, 0x61, - 0x98, 0x7d, 0x68, 0xd6, 0xc9, 0x52, 0xd2, 0x04, 0xe8, 0x82, 0x7a, 0xfc, 0xd2, 0xbf, 0xe3, 0xd6, - 0xa6, 0x5b, 0x6a, 0x8e, 0xb9, 0x2b, 0x62, 0x96, 0xe8, 0x4d, 0x20, 0x96, 0x9a, 0xad, 0x3c, 0x6e, - 0x6d, 0x78, 0x8a, 0xc6, 0xa8, 0xa4, 0xf6, 0x6a, 0xc8, 0x03, 0x78, 0x03, 0x40, 0x53, 0xc0, 0x6a, - 0xc8, 0x0d, 0x0f, 0x7f, 0x85, 0x3a, 0x4e, 0x20, 0x44, 0x68, 0x27, 0x37, 0x34, 0x66, 0xb6, 0x2b, - 0x66, 0x91, 0xd4, 0x5b, 0xd0, 0xb1, 0x95, 0xa5, 0xa4, 0x01, 0xe0, 0xa5, 0xc2, 0x12, 0xab, 0x55, - 0x3a, 0x23, 0x95, 0x87, 0x4d, 0xd4, 0x98, 0x08, 0x21, 0x79, 0x9c, 0x2b, 0x6c, 0x03, 0xed, 0x20, - 0x4b, 0x09, 0xca, 0xc3, 0x20, 0x6f, 0xcd, 0xc6, 0x2e, 0xea, 0x30, 0xce, 0x7c, 0x97, 0x4a, 0xae, - 0x7a, 0x05, 0xb3, 0x30, 0x4a, 0xf4, 0x0e, 0x6c, 0xf3, 0x8b, 0x62, 0x9b, 0xed, 0xf1, 0x32, 0x61, - 0x94, 0xe3, 0x59, 0x4a, 0xba, 0x6c, 0x2b, 0xf6, 0x41, 0x84, 0xbe, 0xba, 0x11, 0xf9, 0x9b, 0xd5, - 0xde, 0xc6, 0xf0, 0x8f, 0x08, 0xc7, 0x7c, 0x1a, 0xa8, 0xa0, 0xfa, 0xd4, 0x13, 0xea, 0x4a, 0x11, - 0xeb, 0x18, 0x86, 0x23, 0x59, 0x4a, 0xde, 0xad, 0xa1, 0xdf, 0x00, 0xb8, 0x56, 0xae, 0xf3, 0x0c, - 0x3c, 0xfc, 0x5d, 0x43, 0x78, 0x94, 0xbf, 0x06, 0xce, 0xca, 0xbb, 0x3f, 0x45, 0x28, 0xbf, 0xe8, - 0x90, 0x4b, 0x0a, 0xa7, 0xdf, 0x38, 0x7e, 0x6b, 0x94, 0xbf, 0x1d, 0x63, 0x95, 0x3a, 0xac, 0x29, - 0x6d, 0x8f, 0xa9, 0xba, 0x13, 0x67, 0xc5, 0xff, 0x0e, 0x1d, 0xb8, 0xcb, 0xaa, 0xf9, 0xb5, 0xec, - 0xbc, 0x78, 0x2d, 0x50, 0x08, 0x4e, 0xa4, 0xb9, 0xe2, 0x2a, 0xf4, 0xf0, 0x0f, 0x0d, 0x35, 0x8a, - 0x4b, 0x57, 0x8f, 0x09, 0x8f, 0x10, 0x72, 0x63, 0x0e, 0x6b, 0xa6, 0xb2, 0x18, 0xee, 0xe3, 0x0a, - 0xd7, 0x0b, 0xde, 0xd7, 0x12, 0xbf, 0x47, 0xbb, 0xa0, 0x6d, 0xa7, 0xff, 0xea, 0x7f, 0xb5, 0x59, - 0x90, 0x82, 0xcf, 0xd6, 0xc5, 0x00, 0xe9, 0x15, 0x90, 0x7a, 0xeb, 0xa4, 0xe7, 0x4b, 0x5c, 0x93, - 0x01, 0x8b, 0x7a, 0xff, 0xb0, 0xe8, 0x69, 0x8f, 0x8b, 0x9e, 0xf6, 0xcf, 0xa2, 0xa7, 0xdd, 0x3f, - 0xf5, 0x2a, 0x8f, 0x4f, 0xbd, 0xca, 0x9f, 0x4f, 0xbd, 0xca, 0xcf, 0xad, 0xad, 0x9f, 0xbd, 0xb3, - 0x07, 0x2a, 0x3e, 0xff, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x02, 0x6e, 0xb1, 0xc7, 0x06, 0x06, 0x00, - 0x00, + // 792 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x54, 0x5f, 0x6b, 0xe3, 0x46, + 0x10, 0xb7, 0x72, 0xb9, 0xd8, 0x5e, 0xc7, 0xb1, 0xbd, 0xc7, 0x81, 0xea, 0x03, 0xaf, 0x09, 0xa5, + 0xf8, 0xe0, 0x2a, 0x91, 0x2b, 0x57, 0x28, 0x85, 0x83, 0xda, 0xbe, 0x42, 0x4a, 0xff, 0x04, 0x25, + 0x79, 0x29, 0x05, 0xb1, 0xd2, 0xae, 0x15, 0x35, 0x92, 0xd6, 0x48, 0x6b, 0xd3, 0xe6, 0x53, 0xe4, + 0xb3, 0xf4, 0x33, 0xf4, 0x21, 0x8f, 0x79, 0x2c, 0x7d, 0x50, 0x8b, 0xf3, 0x26, 0xfa, 0x21, 0xca, + 0x8e, 0x64, 0xc9, 0x76, 0x68, 0xf3, 0x36, 0x33, 0xbf, 0xf9, 0xcd, 0xcc, 0x6f, 0xb4, 0x23, 0xf4, + 0x4a, 0xf2, 0x70, 0x2e, 0x98, 0x63, 0x3a, 0xd4, 0xbd, 0xe6, 0x11, 0x33, 0x97, 0x27, 0xe6, 0xf2, + 0xc4, 0x98, 0xc7, 0x42, 0x0a, 0x8c, 0x8a, 0xa0, 0xb1, 0x3c, 0xe9, 0x13, 0x4f, 0x08, 0x2f, 0xe0, + 0x26, 0x20, 0xce, 0x62, 0x66, 0x4a, 0x3f, 0xe4, 0x89, 0xa4, 0xe1, 0x3c, 0x4f, 0xee, 0x7f, 0xea, + 0xf9, 0xf2, 0x6a, 0xe1, 0x18, 0xae, 0x08, 0x4d, 0x4f, 0x78, 0xa2, 0xca, 0x54, 0x1e, 0x38, 0x60, + 0xe5, 0xe9, 0xc7, 0xff, 0xd4, 0x51, 0x73, 0x1c, 0x08, 0xf7, 0xfa, 0x3b, 0x2e, 0x29, 0xfe, 0x18, + 0xd5, 0x97, 0x3c, 0x4e, 0x7c, 0x11, 0xe9, 0xda, 0x50, 0x1b, 0x35, 0xc7, 0x28, 0x4b, 0xc9, 0xc1, + 0x4c, 0xc4, 0x21, 0x95, 0xd6, 0x1a, 0xc2, 0x36, 0x6a, 0x38, 0x8a, 0x62, 0xfb, 0x4c, 0xdf, 0x1b, + 0x6a, 0xa3, 0xc3, 0xf1, 0xf4, 0x2e, 0x25, 0xb5, 0x3f, 0x53, 0xf2, 0xc9, 0x66, 0xf3, 0x98, 0xce, + 0x68, 0x44, 0x4d, 0x50, 0x66, 0xce, 0xaf, 0x3d, 0x73, 0xb1, 0xf0, 0x99, 0x71, 0x79, 0x79, 0x3a, + 0x5d, 0xa5, 0xa4, 0x0e, 0x4d, 0x4f, 0xa7, 0x59, 0x4a, 0xea, 0x4e, 0x6e, 0x5a, 0x85, 0xc1, 0xf0, + 0x3b, 0xd4, 0x94, 0x3c, 0xa2, 0x91, 0x54, 0x1d, 0x9e, 0xc3, 0x20, 0xfa, 0x2a, 0x25, 0x8d, 0x0b, + 0x08, 0x02, 0xa9, 0x21, 0x0b, 0xdb, 0x5a, 0x5b, 0x0c, 0x9f, 0x21, 0x94, 0x48, 0x1a, 0x4b, 0x5b, + 0xed, 0x44, 0x3f, 0x18, 0x6a, 0xa3, 0xd6, 0xdb, 0xbe, 0x91, 0x2f, 0xcc, 0x58, 0xaf, 0xc1, 0xb8, + 0x58, 0x2f, 0x6c, 0xfc, 0x52, 0x4d, 0x9d, 0xa5, 0xa4, 0x09, 0x2c, 0x15, 0xbf, 0xfd, 0x8b, 0x68, + 0x56, 0xe5, 0xe2, 0x6f, 0x50, 0x83, 0x47, 0x2c, 0xaf, 0x57, 0x7f, 0xb2, 0xde, 0x8b, 0xa2, 0x5e, + 0x9d, 0x47, 0xac, 0xac, 0xb6, 0x76, 0xf0, 0x3b, 0xd4, 0x96, 0x42, 0xd2, 0xc0, 0x16, 0xce, 0xcf, + 0xdc, 0x95, 0x89, 0xde, 0x18, 0x6a, 0xa3, 0xe7, 0xe3, 0x6e, 0x96, 0x92, 0x43, 0x00, 0x7e, 0xc8, + 0xe3, 0xd6, 0x96, 0x87, 0x31, 0xda, 0x4f, 0xfc, 0x1b, 0xae, 0x37, 0x87, 0xda, 0x68, 0xdf, 0x02, + 0x1b, 0xbf, 0x47, 0x5d, 0x57, 0x84, 0x73, 0xea, 0x4a, 0x5f, 0x44, 0x76, 0xc0, 0x97, 0x3c, 0xd0, + 0xd1, 0x50, 0x1b, 0xb5, 0xc7, 0x2f, 0xb2, 0x94, 0x74, 0x2a, 0xec, 0x5b, 0x05, 0x59, 0xbb, 0x01, + 0xfc, 0x46, 0xc9, 0x72, 0x05, 0xf3, 0x23, 0x4f, 0x6f, 0xc1, 0x07, 0xec, 0x16, 0x1f, 0xb0, 0xf1, + 0xa1, 0x88, 0x5b, 0x65, 0x06, 0xfe, 0x02, 0x75, 0xfc, 0x88, 0xf1, 0x5f, 0xec, 0x39, 0xf5, 0xb8, + 0x0d, 0xc3, 0x1c, 0x42, 0xb3, 0x5e, 0x96, 0x92, 0x36, 0x40, 0x67, 0xd4, 0xe3, 0xe7, 0xfe, 0x0d, + 0xb7, 0xb6, 0xdd, 0x4a, 0x73, 0xcc, 0x5d, 0x11, 0xb3, 0x44, 0x6f, 0x03, 0xb1, 0xd2, 0x6c, 0xe5, + 0x71, 0x6b, 0xcb, 0x53, 0x34, 0x46, 0x25, 0xb5, 0xcb, 0x21, 0x8f, 0xe0, 0x0d, 0x00, 0x4d, 0x01, + 0xe5, 0x90, 0x5b, 0x1e, 0xfe, 0x12, 0xf5, 0x9c, 0x40, 0x88, 0xd0, 0x4e, 0xae, 0x68, 0xcc, 0x6c, + 0x57, 0x2c, 0x22, 0xa9, 0x77, 0xa0, 0x63, 0x27, 0x4b, 0x49, 0x0b, 0xc0, 0x73, 0x85, 0x25, 0x56, + 0xa7, 0x72, 0x26, 0x2a, 0x0f, 0x9b, 0xa8, 0x35, 0x13, 0x42, 0xf2, 0x38, 0x57, 0xd8, 0x05, 0xda, + 0x51, 0x96, 0x12, 0x94, 0x87, 0x41, 0xde, 0x86, 0x8d, 0x5d, 0xd4, 0x63, 0x9c, 0xf9, 0x2e, 0x95, + 0x5c, 0xf5, 0x0a, 0x16, 0x61, 0x94, 0xe8, 0x3d, 0xd8, 0xe6, 0xe7, 0xc5, 0x36, 0xbb, 0xd3, 0x75, + 0xc2, 0x24, 0xc7, 0xb3, 0x94, 0xf4, 0xd9, 0x4e, 0xec, 0x8d, 0x08, 0x7d, 0x75, 0x23, 0xf2, 0x57, + 0xab, 0xbb, 0x8b, 0xe1, 0xef, 0x11, 0x8e, 0xf9, 0x3c, 0x50, 0x41, 0xf5, 0xa9, 0x67, 0xd4, 0x95, + 0x22, 0xd6, 0x31, 0x0c, 0x47, 0xb2, 0x94, 0xbc, 0xda, 0x40, 0xbf, 0x06, 0x70, 0xa3, 0x5c, 0xef, + 0x11, 0x78, 0xfc, 0x9b, 0x86, 0xf0, 0x24, 0x7f, 0x0d, 0x9c, 0x55, 0x77, 0xff, 0x1e, 0xa1, 0xfc, + 0xa2, 0x43, 0x2e, 0x29, 0x9c, 0x7e, 0xeb, 0xed, 0x4b, 0xa3, 0xfa, 0xed, 0x18, 0x65, 0xea, 0xb8, + 0xa1, 0xb4, 0xdd, 0xa7, 0xea, 0x4e, 0x9c, 0x92, 0xff, 0x13, 0x3a, 0x72, 0xd7, 0x55, 0xf3, 0x6b, + 0xd9, 0x7b, 0xf2, 0x5a, 0x3e, 0x2a, 0xae, 0xa5, 0x5d, 0x32, 0xcb, 0x9b, 0xd9, 0x0e, 0x1d, 0xff, + 0xae, 0xa1, 0x56, 0x71, 0xfa, 0xea, 0x75, 0xe1, 0x09, 0x42, 0x6e, 0xcc, 0x61, 0xef, 0x54, 0x16, + 0xd3, 0xfe, 0x5f, 0x27, 0x18, 0x39, 0x3f, 0xed, 0x82, 0xf7, 0x95, 0xc4, 0xaf, 0xd1, 0x3e, 0x88, + 0xdd, 0x1b, 0x3e, 0xfb, 0x4f, 0xb1, 0x16, 0xa4, 0xe0, 0x0f, 0x9b, 0xea, 0x80, 0xf4, 0x0c, 0x48, + 0x83, 0x4d, 0xd2, 0xe3, 0xad, 0x6e, 0xc8, 0x80, 0xcd, 0xbd, 0xbe, 0x5b, 0x0d, 0xb4, 0xfb, 0xd5, + 0x40, 0xfb, 0x7b, 0x35, 0xd0, 0x6e, 0x1f, 0x06, 0xb5, 0xfb, 0x87, 0x41, 0xed, 0x8f, 0x87, 0x41, + 0xed, 0xc7, 0xce, 0xce, 0xdf, 0xdf, 0x39, 0x00, 0x15, 0x9f, 0xfd, 0x1b, 0x00, 0x00, 0xff, 0xff, + 0x7f, 0x53, 0x3d, 0xda, 0x17, 0x06, 0x00, 0x00, } func (m *BlockMeta) Marshal() (dAtA []byte, err error) { diff --git a/tempodb/backend/v1/v1.proto b/tempodb/backend/v1/v1.proto index 80747906735..4be72e24e0a 100644 --- a/tempodb/backend/v1/v1.proto +++ b/tempodb/backend/v1/v1.proto @@ -28,7 +28,7 @@ message BlockMeta { message CompactedBlockMeta { BlockMeta block_meta = 1[(gogoproto.embed) = true, (gogoproto.nullable) = false]; - google.protobuf.Timestamp compacted_time = 2[(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; + google.protobuf.Timestamp compacted_time = 2[(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = "compactedTime"]; } message TenantIndex { From 731636669818dc7852c6a18efcf9ccfa566c3ac9 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Thu, 12 Sep 2024 16:07:59 +0000 Subject: [PATCH 29/71] Implement UnmarshalJson on CompcatedBlockMeta for embedded struct --- tempodb/backend/block_meta.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tempodb/backend/block_meta.go b/tempodb/backend/block_meta.go index 43c4dbc4513..6b6e6f5d43f 100644 --- a/tempodb/backend/block_meta.go +++ b/tempodb/backend/block_meta.go @@ -325,3 +325,25 @@ func (dcs DedicatedColumns) MarshalTo(data []byte) (n int, err error) { func (dcs DedicatedColumns) Unmarshal(data []byte) error { return json.Unmarshal(data, &dcs) } + +func (b *CompactedBlockMeta) UnmarshalJSON(data []byte) error { + var msg interface{} + err := json.Unmarshal(data, &msg) + if err != nil { + return err + } + msgMap := msg.(map[string]interface{}) + + if v, ok := msgMap["compactedTime"]; ok { + b.CompactedTime, err = time.Parse(time.RFC3339, v.(string)) + if err != nil { + return fmt.Errorf("failed to parse time at compactedTime: %w", err) + } + } + + if err := json.Unmarshal(data, &b.BlockMeta); err != nil { + return fmt.Errorf("failed at unmarshal for dedicated columns: %w", err) + } + + return nil +} From 151bdcb5181dbc8b69498711a362ac8f38c50858 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Thu, 12 Sep 2024 16:09:54 +0000 Subject: [PATCH 30/71] Test for CompactedMeta marshal/unmarshal --- tempodb/backend/tenantindex_test.go | 1 + tempodb/backend/test/backend_test.go | 30 +++-- .../{meta.json => meta.compacted.json} | 0 .../test-data/single-tenant/index.json.gz | Bin 378 -> 347 bytes tempodb/backend/v1.pb.go | 106 +++++++++--------- tempodb/backend/v1/v1.proto | 4 +- 6 files changed, 78 insertions(+), 63 deletions(-) rename tempodb/backend/test/test-data/single-tenant/05d4e1b5-bed7-42fe-a392-ca807fdb0214/{meta.json => meta.compacted.json} (100%) diff --git a/tempodb/backend/tenantindex_test.go b/tempodb/backend/tenantindex_test.go index 2f00d75398c..cf26e102b1d 100644 --- a/tempodb/backend/tenantindex_test.go +++ b/tempodb/backend/tenantindex_test.go @@ -81,6 +81,7 @@ func TestIndexMarshalUnmarshal(t *testing.T) { require.NoError(t, err) // cmp.Equal used due to time marshalling: https://github.com/stretchr/testify/issues/502 + // assert.Equal(t, tc.idx, actual) assert.True(t, cmp.Equal(tc.idx, actual)) } } diff --git a/tempodb/backend/test/backend_test.go b/tempodb/backend/test/backend_test.go index e2b3707b0f7..a2316a6936b 100644 --- a/tempodb/backend/test/backend_test.go +++ b/tempodb/backend/test/backend_test.go @@ -24,7 +24,7 @@ func TestFixtures(t *testing.T) { // backend.NewBlockMeta(tenant, uuid.New().UUID, "v4", backend.EncLZ4_1M, "adsf"), // } - rr, rw, _, err := local.New(&local.Config{ + rr, rw, rc, err := local.New(&local.Config{ Path: "./test-data", }) require.NoError(t, err) @@ -34,6 +34,9 @@ func TestFixtures(t *testing.T) { r = backend.NewReader(rr) ) + // err = rc.MarkBlockCompacted(uuid.MustParse("05d4e1b5-bed7-42fe-a392-ca807fdb0214"), tenant) + // assert.NoError(t, err) + _, err = r.TenantIndex(ctx, tenant) assert.NoError(t, err) @@ -44,7 +47,7 @@ func TestFixtures(t *testing.T) { listMetas, listCompactedMetas, err := rr.ListBlocks(ctx, tenant) require.NoError(t, err) - require.Len(t, listCompactedMetas, 0) + require.Len(t, listCompactedMetas, 1) for _, v := range listMetas { t.Logf("listMetas: %v", v) @@ -52,14 +55,22 @@ func TestFixtures(t *testing.T) { blockMetas := make([]*backend.BlockMeta, 0, len(listMetas)) for _, u := range listMetas { - meta, e := r.BlockMeta(ctx, u, tenant) + m, e := r.BlockMeta(ctx, u, tenant) require.NoError(t, e) - blockMetas = append(blockMetas, meta) - require.Equal(t, tenant, meta.TenantID) - t.Logf("meta: %v", meta) + blockMetas = append(blockMetas, m) + assert.Equal(t, tenant, m.TenantID) + } + + compactedBlockMetas := make([]*backend.CompactedBlockMeta, 0, len(listCompactedMetas)) + for _, u := range listCompactedMetas { + m, e := rc.CompactedBlockMeta(u, tenant) + assert.NoError(t, e) + compactedBlockMetas = append(compactedBlockMetas, m) + assert.Equal(t, tenant, m.TenantID) } nonZeroMeta(t, blockMetas) + nonZeroCompactedMeta(t, compactedBlockMetas) err = backend.NewWriter(rw).WriteTenantIndex(ctx, tenant, blockMetas, nil) require.NoError(t, err) @@ -80,8 +91,11 @@ func TestFixtures(t *testing.T) { func nonZeroMeta(t *testing.T, m []*backend.BlockMeta) { for _, v := range m { assert.NotZero(t, v.BlockID, "blockid is zero, id: %v", v.BlockID) - assert.NotZero(t, v.BlockID, "blockid is zero, id: %v", v.BlockID) - assert.NotZero(t, v.BlockID, "blockid is zero, id: %v", v.BlockID) + } +} + +func nonZeroCompactedMeta(t *testing.T, m []*backend.CompactedBlockMeta) { + for _, v := range m { assert.NotZero(t, v.BlockID, "blockid is zero, id: %v", v.BlockID) } } diff --git a/tempodb/backend/test/test-data/single-tenant/05d4e1b5-bed7-42fe-a392-ca807fdb0214/meta.json b/tempodb/backend/test/test-data/single-tenant/05d4e1b5-bed7-42fe-a392-ca807fdb0214/meta.compacted.json similarity index 100% rename from tempodb/backend/test/test-data/single-tenant/05d4e1b5-bed7-42fe-a392-ca807fdb0214/meta.json rename to tempodb/backend/test/test-data/single-tenant/05d4e1b5-bed7-42fe-a392-ca807fdb0214/meta.compacted.json diff --git a/tempodb/backend/test/test-data/single-tenant/index.json.gz b/tempodb/backend/test/test-data/single-tenant/index.json.gz index 150c6be17d290b7399b5d6cc5ebe2ef5237a36e7..ab0297273ba3b0e147bbdf14a397e3f302cdecf6 100644 GIT binary patch delta 334 zcmV-U0kQu20^0(R7JraWi_}06#lK6PQ&RmWo!-6)dJq)Fos;6By1Oz)lWs|xMRu9* zE|XDoF5Z-ZcY3_{sQNuYT7{eB=M4gA(iZ6sl|CpJ$c5fN^LI`SS`X#}bg)Qc2p^wd ztn0$(%7cau;#||$S1%wyul3-RICMEHv^w_ajbY3t(qPSyZGUvoL6gFz?Tu|J$64^= zKnGjnwH>BKAOI05+;t!dyUtfg$$t;D+IW5&zes8u1nMBw%WZpd~sphF1 zAwa1`po6Jo`TmZNaz8!Fp4o@qOR8(W3}tTo@^_K*HeUX(%l&8ml^Sbpvi@8-b${Zr zSGb~2j=g5oqet!0`XM5FJEEq<+KkNX`1Wwkj~3ON{{+lj0}~#jau0RR6305lL%+{FU`0F$_=mH+?% delta 365 zcmV-z0h0dP0{Q}w7JtysiWD&r2Jm;ObC*<->c3|_2#VtFNfD_em9e!uS$e`Ev+TRe z_9!|RZ!QCMD(d@4eh&~fm8$WJRG7e$Wuy^}xwU3$$BFrcvo!W2kKIRTVAU!xeR_aY zwsnu(8)(2UC47JV5+38s>~#()$ Date: Thu, 12 Sep 2024 16:17:35 +0000 Subject: [PATCH 31/71] Drop benchmark index --- .../test-data/benchmark-tenant/index.json.gz | Bin 34019 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tempodb/backend/test/test-data/benchmark-tenant/index.json.gz diff --git a/tempodb/backend/test/test-data/benchmark-tenant/index.json.gz b/tempodb/backend/test/test-data/benchmark-tenant/index.json.gz deleted file mode 100644 index bc0f1d0588f175a4178a31f1684485ca06b99379..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34019 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 Date: Fri, 13 Sep 2024 16:12:51 +0000 Subject: [PATCH 32/71] Clean commented code --- tempodb/backend/tenantindex.go | 76 ---------------------------------- 1 file changed, 76 deletions(-) diff --git a/tempodb/backend/tenantindex.go b/tempodb/backend/tenantindex.go index 29985eb8b2b..2466bfb72f9 100644 --- a/tempodb/backend/tenantindex.go +++ b/tempodb/backend/tenantindex.go @@ -59,79 +59,3 @@ func (b *TenantIndex) unmarshal(buffer []byte) error { d := json.NewDecoder(gzipReader) return d.Decode(b) } - -// func (b *TenantIndex) proto() (*TenantIndex, error) { -// tenantIndex := &TenantIndex{ -// CreatedAt: b.CreatedAt, -// Meta: make([]*BlockMeta, 0, len(b.Meta)), -// CompactedMeta: make([]*CompactedBlockMeta, 0, len(b.CompactedMeta)), -// } -// -// var ( -// err error -// mPb *BlockMeta -// cPb *CompactedBlockMeta -// ) -// -// for _, m := range b.Meta { -// mPb, err = m.ToBackendV1Proto() -// if err != nil { -// return nil, err -// } -// -// tenantIndex.Meta = append(tenantIndex.Meta, mPb) -// } -// -// for _, m := range b.CompactedMeta { -// cPb, err = m.ToBackendV1Proto() -// if err != nil { -// return nil, err -// } -// -// tenantIndex.CompactedMeta = append(tenantIndex.CompactedMeta, cPb) -// } -// -// return tenantIndex, nil -// } - -// func (b *tenantIndex) fromProto(pb *TenantIndex) error { -// b.CreatedAt = pb.CreatedAt -// var ( -// meta = make([]*BlockMeta, 0, len(pb.Meta)) -// compactedMeta = make([]*CompactedBlockMeta, 0, len(pb.CompactedMeta)) -// ) -// -// var ( -// err error -// m *BlockMeta -// c *CompactedBlockMeta -// ) -// -// for _, mPb := range pb.Meta { -// m = &BlockMeta{} -// err = m.FromBackendV1Proto(mPb) -// if err != nil { -// return err -// } -// meta = append(meta, m) -// } -// -// if len(meta) > 0 { -// b.Meta = meta -// } -// -// for _, cPb := range pb.CompactedMeta { -// c = &CompactedBlockMeta{} -// err = c.FromBackendV1Proto(cPb) -// if err != nil { -// return err -// } -// compactedMeta = append(compactedMeta, c) -// } -// -// if len(compactedMeta) > 0 { -// b.CompactedMeta = compactedMeta -// } -// -// return nil -// } From 8e8c831f91e200b108f80424d22c153c5930e12f Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Fri, 13 Sep 2024 20:03:31 +0000 Subject: [PATCH 33/71] Extend mocks to capture multiple writes --- tempodb/backend/mocks.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tempodb/backend/mocks.go b/tempodb/backend/mocks.go index 15f5dcbc836..5b747fe6412 100644 --- a/tempodb/backend/mocks.go +++ b/tempodb/backend/mocks.go @@ -72,7 +72,7 @@ func (m *MockRawReader) Shutdown() {} // MockRawWriter type MockRawWriter struct { - writeBuffer []byte + writeBuffer [][]byte appendBuffer []byte closeAppendCalled bool deleteCalls map[string]map[string]int @@ -80,8 +80,13 @@ type MockRawWriter struct { } func (m *MockRawWriter) Write(_ context.Context, _ string, _ KeyPath, data io.Reader, size int64, _ *CacheInfo) error { - var err error - m.writeBuffer, err = tempo_io.ReadAllWithEstimate(data, size) + if m.writeBuffer == nil { + m.writeBuffer = make([][]byte, 0) + } + + writeBuffer, err := tempo_io.ReadAllWithEstimate(data, size) + m.writeBuffer = append(m.writeBuffer, writeBuffer) + return err } From 2142214182930032fce53644273ca33eb47c04f6 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Fri, 13 Sep 2024 20:05:33 +0000 Subject: [PATCH 34/71] Update backend/test fixtures --- .../meta.compacted.json | 2 +- .../meta.compacted.pb | Bin 0 -> 75 bytes .../meta.json | 2 +- .../meta.pb | Bin 0 -> 75 bytes .../meta.json | 2 +- .../meta.pb | Bin 0 -> 75 bytes .../meta.json | 2 +- .../meta.pb | Bin 0 -> 75 bytes .../test/test-data/single-tenant/index.json.gz | Bin 347 -> 409 bytes .../test/test-data/single-tenant/index.pb | Bin 0 -> 338 bytes 10 files changed, 4 insertions(+), 4 deletions(-) rename tempodb/backend/test/test-data/single-tenant/{05d4e1b5-bed7-42fe-a392-ca807fdb0214 => 66610181-fb0d-4b4c-be2f-cea4a87f4c86}/meta.compacted.json (78%) create mode 100644 tempodb/backend/test/test-data/single-tenant/66610181-fb0d-4b4c-be2f-cea4a87f4c86/meta.compacted.pb rename tempodb/backend/test/test-data/single-tenant/{522761e6-6dd1-42b5-833a-d3b07437d4b6 => 9a5dbb1c-f2bc-4414-aae2-1e7a16b4a06c}/meta.json (78%) create mode 100644 tempodb/backend/test/test-data/single-tenant/9a5dbb1c-f2bc-4414-aae2-1e7a16b4a06c/meta.pb rename tempodb/backend/test/test-data/single-tenant/{beafbedc-0dc6-4aa1-b404-3d4e00e08613 => abda0e34-63a1-4379-8c40-8ad6bac8cb85}/meta.json (78%) create mode 100644 tempodb/backend/test/test-data/single-tenant/abda0e34-63a1-4379-8c40-8ad6bac8cb85/meta.pb rename tempodb/backend/test/test-data/single-tenant/{b8c6a82a-2f45-487b-a84f-20ca23faaa6a => cfc82d55-7c16-4dfc-a298-e514224b7e19}/meta.json (78%) create mode 100644 tempodb/backend/test/test-data/single-tenant/cfc82d55-7c16-4dfc-a298-e514224b7e19/meta.pb create mode 100644 tempodb/backend/test/test-data/single-tenant/index.pb diff --git a/tempodb/backend/test/test-data/single-tenant/05d4e1b5-bed7-42fe-a392-ca807fdb0214/meta.compacted.json b/tempodb/backend/test/test-data/single-tenant/66610181-fb0d-4b4c-be2f-cea4a87f4c86/meta.compacted.json similarity index 78% rename from tempodb/backend/test/test-data/single-tenant/05d4e1b5-bed7-42fe-a392-ca807fdb0214/meta.compacted.json rename to tempodb/backend/test/test-data/single-tenant/66610181-fb0d-4b4c-be2f-cea4a87f4c86/meta.compacted.json index c99c183c737..9ddcc4d202e 100644 --- a/tempodb/backend/test/test-data/single-tenant/05d4e1b5-bed7-42fe-a392-ca807fdb0214/meta.compacted.json +++ b/tempodb/backend/test/test-data/single-tenant/66610181-fb0d-4b4c-be2f-cea4a87f4c86/meta.compacted.json @@ -1 +1 @@ -{"format":"v1","blockID":"05d4e1b5-bed7-42fe-a392-ca807fdb0214","tenantID":"single-tenant","startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z","totalObjects":0,"compactionLevel":0,"encoding":"gzip","indexPageSize":0,"totalRecords":0,"dataEncoding":"adsf","bloomShards":0,"footerSize":0} \ No newline at end of file +{"format":"v1","blockID":"66610181-fb0d-4b4c-be2f-cea4a87f4c86","tenantID":"single-tenant","startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z","totalObjects":0,"compactionLevel":0,"encoding":"gzip","indexPageSize":0,"totalRecords":0,"dataEncoding":"adsf","bloomShards":0,"footerSize":0} \ No newline at end of file diff --git a/tempodb/backend/test/test-data/single-tenant/66610181-fb0d-4b4c-be2f-cea4a87f4c86/meta.compacted.pb b/tempodb/backend/test/test-data/single-tenant/66610181-fb0d-4b4c-be2f-cea4a87f4c86/meta.compacted.pb new file mode 100644 index 0000000000000000000000000000000000000000..776259e45edf13ed156f0f9c6acc9c4190dd923e GIT binary patch literal 75 zcmd;LDl-%kNK0gF{LSm_vrqrrk`?tnZCbp=nR)3ssk$Ypd5L)?M%)|?lXe`Q@$dit V|BP11oG3=6^s3APrL-P literal 0 HcmV?d00001 diff --git a/tempodb/backend/test/test-data/single-tenant/522761e6-6dd1-42b5-833a-d3b07437d4b6/meta.json b/tempodb/backend/test/test-data/single-tenant/9a5dbb1c-f2bc-4414-aae2-1e7a16b4a06c/meta.json similarity index 78% rename from tempodb/backend/test/test-data/single-tenant/522761e6-6dd1-42b5-833a-d3b07437d4b6/meta.json rename to tempodb/backend/test/test-data/single-tenant/9a5dbb1c-f2bc-4414-aae2-1e7a16b4a06c/meta.json index 76e805a6b9a..161b4af8ff7 100644 --- a/tempodb/backend/test/test-data/single-tenant/522761e6-6dd1-42b5-833a-d3b07437d4b6/meta.json +++ b/tempodb/backend/test/test-data/single-tenant/9a5dbb1c-f2bc-4414-aae2-1e7a16b4a06c/meta.json @@ -1 +1 @@ -{"format":"v2","blockID":"522761e6-6dd1-42b5-833a-d3b07437d4b6","tenantID":"single-tenant","startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z","totalObjects":0,"compactionLevel":0,"encoding":"none","indexPageSize":0,"totalRecords":0,"dataEncoding":"adsf","bloomShards":0,"footerSize":0} \ No newline at end of file +{"format":"v2","blockID":"9a5dbb1c-f2bc-4414-aae2-1e7a16b4a06c","tenantID":"single-tenant","startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z","totalObjects":0,"compactionLevel":0,"encoding":"none","indexPageSize":0,"totalRecords":0,"dataEncoding":"adsf","bloomShards":0,"footerSize":0} \ No newline at end of file diff --git a/tempodb/backend/test/test-data/single-tenant/9a5dbb1c-f2bc-4414-aae2-1e7a16b4a06c/meta.pb b/tempodb/backend/test/test-data/single-tenant/9a5dbb1c-f2bc-4414-aae2-1e7a16b4a06c/meta.pb new file mode 100644 index 0000000000000000000000000000000000000000..910770514b4da856de0cff5181f6562302d31847 GIT binary patch literal 75 zcmd;LDl-xim=(KQ=F=V*kyVf6s>HS|$kF00&df{CN!2Y$%}dNHG2-TEn6%^YjDP?C W|7Wy9=0q_n<>lw4Dy4NXG5`RQJs>Fn literal 0 HcmV?d00001 diff --git a/tempodb/backend/test/test-data/single-tenant/beafbedc-0dc6-4aa1-b404-3d4e00e08613/meta.json b/tempodb/backend/test/test-data/single-tenant/abda0e34-63a1-4379-8c40-8ad6bac8cb85/meta.json similarity index 78% rename from tempodb/backend/test/test-data/single-tenant/beafbedc-0dc6-4aa1-b404-3d4e00e08613/meta.json rename to tempodb/backend/test/test-data/single-tenant/abda0e34-63a1-4379-8c40-8ad6bac8cb85/meta.json index 2834273a8fd..ccdc2089355 100644 --- a/tempodb/backend/test/test-data/single-tenant/beafbedc-0dc6-4aa1-b404-3d4e00e08613/meta.json +++ b/tempodb/backend/test/test-data/single-tenant/abda0e34-63a1-4379-8c40-8ad6bac8cb85/meta.json @@ -1 +1 @@ -{"format":"v3","blockID":"beafbedc-0dc6-4aa1-b404-3d4e00e08613","tenantID":"single-tenant","startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z","totalObjects":0,"compactionLevel":0,"encoding":"lz4","indexPageSize":0,"totalRecords":0,"dataEncoding":"adsf","bloomShards":0,"footerSize":0} \ No newline at end of file +{"format":"v3","blockID":"abda0e34-63a1-4379-8c40-8ad6bac8cb85","tenantID":"single-tenant","startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z","totalObjects":0,"compactionLevel":0,"encoding":"lz4","indexPageSize":0,"totalRecords":0,"dataEncoding":"adsf","bloomShards":0,"footerSize":0} \ No newline at end of file diff --git a/tempodb/backend/test/test-data/single-tenant/abda0e34-63a1-4379-8c40-8ad6bac8cb85/meta.pb b/tempodb/backend/test/test-data/single-tenant/abda0e34-63a1-4379-8c40-8ad6bac8cb85/meta.pb new file mode 100644 index 0000000000000000000000000000000000000000..663409beb1ce820ba1c39e310ae76f22f8609f50 GIT binary patch literal 75 zcmd;LDl--mSbdAnBzd88WsgJGwOuDpw`%bgXXd5nr0SNW<|XEp7;$qnOxkgH#=rmn V|1(-4bD|iPa;i*}iqpCn8345xAie+q literal 0 HcmV?d00001 diff --git a/tempodb/backend/test/test-data/single-tenant/b8c6a82a-2f45-487b-a84f-20ca23faaa6a/meta.json b/tempodb/backend/test/test-data/single-tenant/cfc82d55-7c16-4dfc-a298-e514224b7e19/meta.json similarity index 78% rename from tempodb/backend/test/test-data/single-tenant/b8c6a82a-2f45-487b-a84f-20ca23faaa6a/meta.json rename to tempodb/backend/test/test-data/single-tenant/cfc82d55-7c16-4dfc-a298-e514224b7e19/meta.json index aa3a30171d2..868f799643c 100644 --- a/tempodb/backend/test/test-data/single-tenant/b8c6a82a-2f45-487b-a84f-20ca23faaa6a/meta.json +++ b/tempodb/backend/test/test-data/single-tenant/cfc82d55-7c16-4dfc-a298-e514224b7e19/meta.json @@ -1 +1 @@ -{"format":"v4","blockID":"b8c6a82a-2f45-487b-a84f-20ca23faaa6a","tenantID":"single-tenant","startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z","totalObjects":0,"compactionLevel":0,"encoding":"lz4-1M","indexPageSize":0,"totalRecords":0,"dataEncoding":"adsf","bloomShards":0,"footerSize":0} \ No newline at end of file +{"format":"v4","blockID":"cfc82d55-7c16-4dfc-a298-e514224b7e19","tenantID":"single-tenant","startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z","totalObjects":0,"compactionLevel":0,"encoding":"lz4-1M","indexPageSize":0,"totalRecords":0,"dataEncoding":"adsf","bloomShards":0,"footerSize":0} \ No newline at end of file diff --git a/tempodb/backend/test/test-data/single-tenant/cfc82d55-7c16-4dfc-a298-e514224b7e19/meta.pb b/tempodb/backend/test/test-data/single-tenant/cfc82d55-7c16-4dfc-a298-e514224b7e19/meta.pb new file mode 100644 index 0000000000000000000000000000000000000000..e78db268d304652dfa7aca8187c1f5df093fe031 GIT binary patch literal 75 zcmd;LDl-uhIDbMnv_{PL&!QPmMU=ejB(->pGxO4OQgusG^Aht)jJP=(Cha&pgviEopdjmW|3Lu zzsqJ;-GRm1%0Qip_a3i5=(-14l#9mK1qN`&5t<%ty|LX;*F)o8^|dukZN0yS3T7<~ z!NgW5BOZQEL7y~Qz@h!jXLs2fp~iG4Sc`1bM` rZV%J#ixGUn@3Hl>chGg6r-qtqINlt80RRC1{{sN+Nd{&bI0XOz@xI04 delta 334 zcmV-U0kQs>1KR?S7JraWi_}06#lK6PQ&RmWo!-6)dJq)Fos;6By1Oz)lWs|xMRu9* zE|XDoF5Z-ZcY3_{sQNuYT7{eB=M4gA(iZ6sl|CpJ$c5fN^LI`SS`X#}bg)Qc2p^wd ztn0$(%7cau;#||$S1%wyul3-RICMEHv^w_ajbY3t(qPSyZGUvoL6gFz?Tu|J$64^= zKnGjnwH>BKAOI05+;t!dyUtfg$$t;D+IW5&zes8u1nMBw%WZpd~sphF1 zAwa1`po6Jo`TmZNaz8!Fp4o@qOR8(W3}tTo@^_K*HeUX(%l&8ml^Sbpvi@8-b${Zr zSGb~2j=g5oqet!0`XM5FJEEq<+KkNX`1Wwkj~3ON{{+lj0}~#jau0RR6305lL%+{FU`02X(sHUIzs diff --git a/tempodb/backend/test/test-data/single-tenant/index.pb b/tempodb/backend/test/test-data/single-tenant/index.pb new file mode 100644 index 0000000000000000000000000000000000000000..43cb922a5e40db3fbad5e415d8e701105a74ae5b GIT binary patch literal 338 zcmd<$;b?e2aXXtp%imwSnT5Q$n97WV1ZKtVmie^DMP$_@xhkGj0|AIjD-YN-{Lb#Ug%ueAt{KZ|BO6;bl8lO)kFT|-|bMh2;9E|5nJg#^+P k85@7|di(6tKeuE>y-yn{#-&$f7C<}-3&V$dHt%8v04+I Date: Fri, 13 Sep 2024 20:40:55 +0000 Subject: [PATCH 35/71] Write both proto and json to the backend for all three files in all backends --- tempodb/backend/azure/azure.go | 3 + tempodb/backend/azure/compactor.go | 51 ++++++++++- tempodb/backend/backend.go | 4 + tempodb/backend/block_meta.go | 25 +++--- tempodb/backend/encoding.go | 11 ++- tempodb/backend/gcs/compactor.go | 52 ++++++++++- tempodb/backend/gcs/gcs.go | 4 + tempodb/backend/local/compactor.go | 43 +++++++++ tempodb/backend/local/local.go | 4 + tempodb/backend/raw.go | 115 +++++++++++++++++++++++-- tempodb/backend/raw_test.go | 44 +++++++++- tempodb/backend/s3/compactor.go | 52 ++++++++++- tempodb/backend/s3/s3.go | 4 +- tempodb/backend/test/backend_test.go | 26 +++--- tempodb/backend/test/benchmark_test.go | 1 + tempodb/backend/v1.pb.go | 33 +++---- tempodb/backend/v1/v1.proto | 1 + 17 files changed, 409 insertions(+), 64 deletions(-) diff --git a/tempodb/backend/azure/azure.go b/tempodb/backend/azure/azure.go index fc4c7f64940..782d10d7b3e 100644 --- a/tempodb/backend/azure/azure.go +++ b/tempodb/backend/azure/azure.go @@ -19,6 +19,7 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blockblob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container" + gkLog "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/google/uuid" "github.com/grafana/tempo/pkg/util/log" @@ -36,6 +37,7 @@ const ( ) type Azure struct { + logger gkLog.Logger cfg *Config containerClient *container.Client hedgedContainerClient *container.Client @@ -95,6 +97,7 @@ func internalNew(cfg *Config, confirm bool) (*Azure, error) { } rw := &Azure{ + logger: log.Logger, cfg: cfg, containerClient: c, hedgedContainerClient: hedgedContainer, diff --git a/tempodb/backend/azure/compactor.go b/tempodb/backend/azure/compactor.go index 4c2c494e63c..6eaa7e814e9 100644 --- a/tempodb/backend/azure/compactor.go +++ b/tempodb/backend/azure/compactor.go @@ -8,6 +8,7 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container" + "github.com/go-kit/log/level" "github.com/google/uuid" "github.com/grafana/tempo/tempodb/backend" @@ -29,10 +30,30 @@ func (rw *Azure) MarkBlockCompacted(blockID uuid.UUID, tenantID string) error { return backend.ErrEmptyBlockID } - // move meta file to a new location + ctx := context.TODO() + + // move meta files to a new location + metaFilenamePb := backend.MetaFileNamePb(blockID, tenantID, rw.cfg.Prefix) + compactedMetaFilenamePb := backend.CompactedMetaFileNamePb(blockID, tenantID, rw.cfg.Prefix) + + srcPb, _, err := rw.readAll(ctx, metaFilenamePb) + if err != nil { + level.Error(rw.logger).Log("msg", "error copying obj meta.pb to compacted.pb, is this block from previous Tempo version?", "err", err) + } else { + err = rw.writeAll(ctx, compactedMetaFilenamePb, srcPb) + if err != nil { + return err + } + + // delete the old file + err = rw.Delete(ctx, metaFilenamePb, []string{}, nil) + if err != nil { + return err + } + } + metaFilename := backend.MetaFileName(blockID, tenantID, rw.cfg.Prefix) compactedMetaFilename := backend.CompactedMetaFileName(blockID, tenantID, rw.cfg.Prefix) - ctx := context.TODO() src, _, err := rw.readAll(ctx, metaFilename) if err != nil { @@ -96,6 +117,14 @@ func (rw *Azure) CompactedBlockMeta(blockID uuid.UUID, tenantID string) (*backen if blockID == uuid.Nil { return nil, backend.ErrEmptyBlockID } + + outPb, err := rw.compactedBlockMetaPb(blockID, tenantID) + if err == nil { + return outPb, nil + } + + // TODO: record a note about the fallback + name := backend.CompactedMetaFileName(blockID, tenantID, rw.cfg.Prefix) bytes, modTime, err := rw.readAllWithModTime(context.Background(), name) @@ -113,6 +142,24 @@ func (rw *Azure) CompactedBlockMeta(blockID uuid.UUID, tenantID string) (*backen return out, nil } +func (rw *Azure) compactedBlockMetaPb(blockID uuid.UUID, tenantID string) (*backend.CompactedBlockMeta, error) { + name := backend.CompactedMetaFileNamePb(blockID, tenantID, rw.cfg.Prefix) + + bytes, modTime, err := rw.readAllWithModTime(context.Background(), name) + if err != nil { + return nil, readError(err) + } + + out := &backend.CompactedBlockMeta{} + err = out.Unmarshal(bytes) + if err != nil { + return nil, err + } + out.CompactedTime = modTime + + return out, nil +} + func (rw *Azure) readAllWithModTime(ctx context.Context, name string) ([]byte, time.Time, error) { bytes, _, err := rw.readAll(ctx, name) if err != nil { diff --git a/tempodb/backend/backend.go b/tempodb/backend/backend.go index c3a49444b6f..93a1f006d47 100644 --- a/tempodb/backend/backend.go +++ b/tempodb/backend/backend.go @@ -6,6 +6,7 @@ import ( "io" "github.com/google/uuid" + "go.opentelemetry.io/otel" "github.com/grafana/tempo/pkg/cache" ) @@ -24,6 +25,9 @@ var ( ErrBadSeedFile = fmt.Errorf("bad seed file") GlobalMaxBlockID = uuid.MustParse("ffffffff-ffff-ffff-ffff-ffffffffffff") + + tracer = otel.Tracer("backend") + EventJSONFallback = "falling back to json" ) type CacheInfo struct { diff --git a/tempodb/backend/block_meta.go b/tempodb/backend/block_meta.go index 6b6e6f5d43f..bb406d7b93a 100644 --- a/tempodb/backend/block_meta.go +++ b/tempodb/backend/block_meta.go @@ -297,23 +297,24 @@ func (dcs DedicatedColumns) Hash() uint64 { } func (dcs DedicatedColumns) Size() int { - // FIXME: I don't think this is right. Since we're not marshaling to proto. - - var s int - pb, err := dcs.ToTempopb() - if err != nil { + if len(dcs) == 0 { return 0 } - for _, i := range pb { - s += i.Size() + b, _ := dcs.Marshal() + return len(b) +} + +func (dcs DedicatedColumns) Marshal() ([]byte, error) { + if len(dcs) == 0 { + return nil, nil } - return s + return json.Marshal(dcs) } func (dcs DedicatedColumns) MarshalTo(data []byte) (n int, err error) { - bb, err := json.Marshal(dcs) + bb, err := dcs.Marshal() if err != nil { return 0, err } @@ -322,7 +323,11 @@ func (dcs DedicatedColumns) MarshalTo(data []byte) (n int, err error) { return len(bb), nil } -func (dcs DedicatedColumns) Unmarshal(data []byte) error { +func (dcs *DedicatedColumns) Unmarshal(data []byte) error { + if len(data) == 0 { + return nil + } + return json.Unmarshal(data, &dcs) } diff --git a/tempodb/backend/encoding.go b/tempodb/backend/encoding.go index 53414e57342..b715ab324b1 100644 --- a/tempodb/backend/encoding.go +++ b/tempodb/backend/encoding.go @@ -106,7 +106,7 @@ func (e Encoding) MarshalJSON() ([]byte, error) { } func (e Encoding) Marshal() ([]byte, error) { - return e.MarshalJSON() + return []byte{byte(e)}, nil } func (e *Encoding) MarshalTo(data []byte) (n int, err error) { @@ -119,7 +119,14 @@ func (e *Encoding) MarshalTo(data []byte) (n int, err error) { } func (e *Encoding) Unmarshal(data []byte) error { - return e.UnmarshalJSON(data) + if len(data) != 1 { + return fmt.Errorf("invalid data: %s", data) + } + + x := Encoding(data[0]) + *e = x + + return nil } func (e *Encoding) Size() int { diff --git a/tempodb/backend/gcs/compactor.go b/tempodb/backend/gcs/compactor.go index a02c1ff32f3..cb94867bbfc 100644 --- a/tempodb/backend/gcs/compactor.go +++ b/tempodb/backend/gcs/compactor.go @@ -7,6 +7,7 @@ import ( "fmt" "cloud.google.com/go/storage" + "github.com/go-kit/log/level" "github.com/google/uuid" "github.com/googleapis/gax-go/v2" "google.golang.org/api/iterator" @@ -15,7 +16,28 @@ import ( ) func (rw *readerWriter) MarkBlockCompacted(blockID uuid.UUID, tenantID string) error { - // move meta file to a new location + // move meta files to a new location + + metaFilenamePb := backend.MetaFileNamePb(blockID, tenantID, rw.cfg.Prefix) + compactedMetaFilenamePb := backend.CompactedMetaFileNamePb(blockID, tenantID, rw.cfg.Prefix) + + srcPb := rw.bucket.Object(metaFilenamePb) + dstPb := rw.bucket.Object(compactedMetaFilenamePb).Retryer( + storage.WithBackoff(gax.Backoff{}), + storage.WithPolicy(storage.RetryAlways), + ) + + ctx := context.TODO() + _, err := dstPb.CopierFrom(srcPb).Run(ctx) + if err != nil { + level.Error(rw.logger).Log("msg", "error copying obj meta.pb to compacted.pb, is this block from previous Tempo version?", "err", err) + } else { + err = srcPb.Delete(ctx) + if err != nil { + return err + } + } + metaFilename := backend.MetaFileName(blockID, tenantID, rw.cfg.Prefix) compactedMetaFilename := backend.CompactedMetaFileName(blockID, tenantID, rw.cfg.Prefix) @@ -25,8 +47,7 @@ func (rw *readerWriter) MarkBlockCompacted(blockID uuid.UUID, tenantID string) e storage.WithPolicy(storage.RetryAlways), ) - ctx := context.TODO() - _, err := dst.CopierFrom(src).Run(ctx) + _, err = dst.CopierFrom(src).Run(ctx) if err != nil { return err } @@ -69,6 +90,13 @@ func (rw *readerWriter) ClearBlock(blockID uuid.UUID, tenantID string) error { } func (rw *readerWriter) CompactedBlockMeta(blockID uuid.UUID, tenantID string) (*backend.CompactedBlockMeta, error) { + outPb, err := rw.compactedBlockMetaPb(blockID, tenantID) + if err == nil { + return outPb, nil + } + + // TODO: record a note about fallback + name := backend.CompactedMetaFileName(blockID, tenantID, rw.cfg.Prefix) bytes, attrs, err := rw.readAll(context.Background(), name) @@ -85,3 +113,21 @@ func (rw *readerWriter) CompactedBlockMeta(blockID uuid.UUID, tenantID string) ( return out, nil } + +func (rw *readerWriter) compactedBlockMetaPb(blockID uuid.UUID, tenantID string) (*backend.CompactedBlockMeta, error) { + name := backend.CompactedMetaFileNamePb(blockID, tenantID, rw.cfg.Prefix) + + bytes, attrs, err := rw.readAll(context.Background(), name) + if err != nil { + return nil, readError(err) + } + + out := &backend.CompactedBlockMeta{} + err = out.Unmarshal(bytes) + if err != nil { + return nil, err + } + out.CompactedTime = attrs.LastModified + + return out, nil +} diff --git a/tempodb/backend/gcs/gcs.go b/tempodb/backend/gcs/gcs.go index aacb3072fe6..c47d40cbe0e 100644 --- a/tempodb/backend/gcs/gcs.go +++ b/tempodb/backend/gcs/gcs.go @@ -23,16 +23,19 @@ import ( "cloud.google.com/go/storage" "github.com/cristalhq/hedgedhttp" + gkLog "github.com/go-kit/log" "google.golang.org/api/iterator" "google.golang.org/api/option" google_http "google.golang.org/api/transport/http" "github.com/grafana/tempo/pkg/blockboundary" tempo_io "github.com/grafana/tempo/pkg/io" + "github.com/grafana/tempo/pkg/util/log" "github.com/grafana/tempo/tempodb/backend" ) type readerWriter struct { + logger gkLog.Logger cfg *Config bucket *storage.BucketHandle hedgedBucket *storage.BucketHandle @@ -100,6 +103,7 @@ func internalNew(cfg *Config, confirm bool) (*readerWriter, error) { } rw := &readerWriter{ + logger: log.Logger, cfg: cfg, bucket: bucket, hedgedBucket: hedgedBucket, diff --git a/tempodb/backend/local/compactor.go b/tempodb/backend/local/compactor.go index eed15c7bbd0..a0de3128d9a 100644 --- a/tempodb/backend/local/compactor.go +++ b/tempodb/backend/local/compactor.go @@ -7,11 +7,21 @@ import ( "os" "path" + "github.com/go-kit/log/level" "github.com/google/uuid" + "github.com/grafana/tempo/pkg/util/log" "github.com/grafana/tempo/tempodb/backend" ) func (rw *Backend) MarkBlockCompacted(blockID uuid.UUID, tenantID string) error { + metaFilenamePb := rw.metaFileNamePb(blockID, tenantID) + compactedMetaFilenamePb := rw.compactedMetaFileNamePb(blockID, tenantID) + + err := os.Rename(metaFilenamePb, compactedMetaFilenamePb) + if err != nil { + level.Error(log.Logger).Log("msg", "error copying obj meta.pb to compacted.pb, is this block from previous Tempo version?", "err", err) + } + // move meta file to a new location metaFilename := rw.metaFileName(blockID, tenantID) compactedMetaFilename := rw.compactedMetaFileName(blockID, tenantID) @@ -38,6 +48,13 @@ func (rw *Backend) ClearBlock(blockID uuid.UUID, tenantID string) error { } func (rw *Backend) CompactedBlockMeta(blockID uuid.UUID, tenantID string) (*backend.CompactedBlockMeta, error) { + outPb, err := rw.compactedBlockMetaPb(blockID, tenantID) + if err == nil { + return outPb, nil + } + + // TODO: record a note about fallback + filename := rw.compactedMetaFileName(blockID, tenantID) fi, err := os.Stat(filename) @@ -60,6 +77,32 @@ func (rw *Backend) CompactedBlockMeta(blockID uuid.UUID, tenantID string) (*back return out, nil } +func (rw *Backend) compactedBlockMetaPb(blockID uuid.UUID, tenantID string) (*backend.CompactedBlockMeta, error) { + filename := rw.compactedMetaFileNamePb(blockID, tenantID) + fi, err := os.Stat(filename) + if err != nil { + return nil, readError(err) + } + + bytes, err := os.ReadFile(filename) + if err != nil { + return nil, readError(err) + } + + out := &backend.CompactedBlockMeta{} + err = out.Unmarshal(bytes) + if err != nil { + return nil, err + } + out.CompactedTime = fi.ModTime() + + return out, nil +} + func (rw *Backend) compactedMetaFileName(blockID uuid.UUID, tenantID string) string { return path.Join(rw.rootPath(backend.KeyPathForBlock(blockID, tenantID)), backend.CompactedMetaName) } + +func (rw *Backend) compactedMetaFileNamePb(blockID uuid.UUID, tenantID string) string { + return path.Join(rw.rootPath(backend.KeyPathForBlock(blockID, tenantID)), backend.CompactedMetaNamePb) +} diff --git a/tempodb/backend/local/local.go b/tempodb/backend/local/local.go index b75edd585f1..1c6c2e1a795 100644 --- a/tempodb/backend/local/local.go +++ b/tempodb/backend/local/local.go @@ -307,6 +307,10 @@ func (rw *Backend) metaFileName(blockID uuid.UUID, tenantID string) string { return filepath.Join(rw.rootPath(backend.KeyPathForBlock(blockID, tenantID)), backend.MetaName) } +func (rw *Backend) metaFileNamePb(blockID uuid.UUID, tenantID string) string { + return filepath.Join(rw.rootPath(backend.KeyPathForBlock(blockID, tenantID)), backend.MetaNamePb) +} + func (rw *Backend) rootPath(keypath backend.KeyPath) string { return filepath.Join(rw.cfg.Path, filepath.Join(keypath...)) } diff --git a/tempodb/backend/raw.go b/tempodb/backend/raw.go index 0d3bbaf22ec..a3989277dcf 100644 --- a/tempodb/backend/raw.go +++ b/tempodb/backend/raw.go @@ -9,6 +9,7 @@ import ( "path" "time" + proto "github.com/gogo/protobuf/proto" google_uuid "github.com/google/uuid" tempo_io "github.com/grafana/tempo/pkg/io" @@ -20,6 +21,11 @@ const ( CompactedMetaName = "meta.compacted.json" TenantIndexName = "index.json.gz" + // Proto + MetaNamePb = "meta.pb" + CompactedMetaNamePb = "meta.compacted.pb" + TenantIndexNamePb = "index.pb" + // File name for the cluster seed file. ClusterSeedFileName = "tempo_cluster_seed.json" ) @@ -101,6 +107,18 @@ func (w *writer) WriteBlockMeta(ctx context.Context, meta *BlockMeta) error { tenantID = meta.TenantID ) + // marshal and write proto to the backend + mPb, err := proto.Marshal(meta) + if err != nil { + return err + } + + err = w.w.Write(ctx, MetaNamePb, KeyPathForBlock(blockID, tenantID), bytes.NewReader(mPb), int64(len(mPb)), nil) + if err != nil { + return err + } + + // marshal and write json to the backend bMeta, err := json.Marshal(meta) if err != nil { return err @@ -128,22 +146,33 @@ func (w *writer) WriteTenantIndex(ctx context.Context, tenantID string, meta []* if err != nil && !errors.Is(err, ErrDoesNotExist) { return err } + + err = w.w.Delete(ctx, TenantIndexNamePb, []string{tenantID}, nil) + if err != nil && !errors.Is(err, ErrDoesNotExist) { + return err + } + return nil } b := newTenantIndex(meta, compactedMeta) - indexBytes, err := b.marshal() + indexBytesPb, err := proto.Marshal(b) + if err != nil { + return err + } + + err = w.w.Write(ctx, TenantIndexNamePb, KeyPath([]string{tenantID}), bytes.NewReader(indexBytesPb), int64(len(indexBytesPb)), nil) if err != nil { return err } - err = w.w.Write(ctx, TenantIndexName, KeyPath([]string{tenantID}), bytes.NewReader(indexBytes), int64(len(indexBytes)), nil) + indexBytes, err := b.marshal() if err != nil { return err } - return nil + return w.w.Write(ctx, TenantIndexName, KeyPath([]string{tenantID}), bytes.NewReader(indexBytes), int64(len(indexBytes)), nil) } // Delete implements backend.Writer @@ -204,6 +233,16 @@ func (r *reader) Blocks(ctx context.Context, tenantID string) ([]google_uuid.UUI // BlockMeta implements backend.Reader func (r *reader) BlockMeta(ctx context.Context, blockID google_uuid.UUID, tenantID string) (*BlockMeta, error) { + ctx, span := tracer.Start(ctx, "reader.BlockMeta") + defer span.End() + + outPb, err := r.blockMetaPb(ctx, blockID, tenantID) + if err == nil { + return outPb, nil + } + + span.AddEvent(EventJSONFallback) + reader, size, err := r.r.Read(ctx, MetaName, KeyPathForBlock(blockID, tenantID), nil) if err != nil { return nil, err @@ -224,22 +263,53 @@ func (r *reader) BlockMeta(ctx context.Context, blockID google_uuid.UUID, tenant return out, nil } +func (r *reader) blockMetaPb(ctx context.Context, blockID google_uuid.UUID, tenantID string) (*BlockMeta, error) { + // Read proto first, and fall back to json + readerPb, size, err := r.r.Read(ctx, MetaNamePb, KeyPathForBlock(blockID, tenantID), nil) + if err != nil { + return nil, err + } + defer readerPb.Close() + + bytesPb, err := tempo_io.ReadAllWithEstimate(readerPb, size) + if err != nil { + return nil, err + } + + outPb := &BlockMeta{} + err = outPb.Unmarshal(bytesPb) + if err != nil { + return nil, err + } + + return outPb, nil +} + // TenantIndex implements backend.Reader func (r *reader) TenantIndex(ctx context.Context, tenantID string) (*TenantIndex, error) { - reader, size, err := r.r.Read(ctx, TenantIndexName, KeyPath([]string{tenantID}), nil) + ctx, span := tracer.Start(ctx, "reader.TenantIndex") + defer span.End() + + outPb, err := r.tenantIndexProto(ctx, tenantID) + if err == nil { + return outPb, nil + } + + span.AddEvent(EventJSONFallback) + + readerJ, size, err := r.r.Read(ctx, TenantIndexName, KeyPath([]string{tenantID}), nil) if err != nil { return nil, err } + defer readerJ.Close() - defer reader.Close() - - bytes, err := tempo_io.ReadAllWithEstimate(reader, size) + bytesJ, err := tempo_io.ReadAllWithEstimate(readerJ, size) if err != nil { return nil, err } i := &TenantIndex{} - err = i.unmarshal(bytes) + err = i.unmarshal(bytesJ) if err != nil { return nil, err } @@ -247,6 +317,27 @@ func (r *reader) TenantIndex(ctx context.Context, tenantID string) (*TenantIndex return i, nil } +func (r *reader) tenantIndexProto(ctx context.Context, tenantID string) (*TenantIndex, error) { + readerPb, size, err := r.r.Read(ctx, TenantIndexNamePb, KeyPath([]string{tenantID}), nil) + if err != nil { + return nil, err + } + defer readerPb.Close() + + bytesPb, err := tempo_io.ReadAllWithEstimate(readerPb, size) + if err != nil { + return nil, err + } + + out := &TenantIndex{} + err = out.Unmarshal(bytesPb) + if err != nil { + return nil, err + } + + return out, nil +} + // Find implements backend.Reader func (r *reader) Find(ctx context.Context, keypath KeyPath, f FindFunc) error { return r.r.Find(ctx, keypath, f) @@ -281,11 +372,19 @@ func MetaFileName(blockID google_uuid.UUID, tenantID, prefix string) string { return path.Join(prefix, tenantID, blockID.String(), MetaName) } +func MetaFileNamePb(blockID google_uuid.UUID, tenantID, prefix string) string { + return path.Join(prefix, tenantID, blockID.String(), MetaNamePb) +} + // CompactedMetaFileName returns the object name for the compacted block meta given a block id and tenantid func CompactedMetaFileName(blockID google_uuid.UUID, tenantID, prefix string) string { return path.Join(prefix, tenantID, blockID.String(), CompactedMetaName) } +func CompactedMetaFileNamePb(blockID google_uuid.UUID, tenantID, prefix string) string { + return path.Join(prefix, tenantID, blockID.String(), CompactedMetaNamePb) +} + // RootPath returns the root path for a block given a block id and tenantid func RootPath(blockID google_uuid.UUID, tenantID, prefix string) string { return path.Join(prefix, tenantID, blockID.String()) diff --git a/tempodb/backend/raw_test.go b/tempodb/backend/raw_test.go index a5e959296b5..72319d92d46 100644 --- a/tempodb/backend/raw_test.go +++ b/tempodb/backend/raw_test.go @@ -5,6 +5,7 @@ import ( "encoding/json" "testing" + proto "github.com/gogo/protobuf/proto" "github.com/google/go-cmp/cmp" "github.com/google/uuid" "github.com/stretchr/testify/assert" @@ -25,7 +26,7 @@ func TestWriter(t *testing.T) { err := w.Write(ctx, "test", uuid.New(), "test", expected, nil) assert.NoError(t, err) - assert.Equal(t, expected, m.writeBuffer) + assert.Equal(t, expected, m.writeBuffer[len(m.writeBuffer)-1]) _, err = w.Append(ctx, "test", uuid.New(), "test", nil, expected) assert.NoError(t, err) @@ -36,17 +37,52 @@ func TestWriter(t *testing.T) { assert.True(t, m.closeAppendCalled) meta := NewBlockMeta("test", uuid.New(), "blerg", EncGZIP, "glarg") + + // RoundTrip with empty DedicatedColumns + expectedPb, err := meta.Marshal() + assert.NoError(t, err) + expectedPb2 := &BlockMeta{} + err = expectedPb2.Unmarshal(expectedPb) + assert.NoError(t, err) + assert.Equal(t, meta, expectedPb2) + + // RoundTrip with non-empty DedicatedColumns + meta.DedicatedColumns = DedicatedColumns{ + {Scope: "resource", Name: "namespace", Type: "string"}, + {Scope: "span", Name: "http.method", Type: "string"}, + {Scope: "span", Name: "namespace", Type: "string"}, + } + + expectedPb, err = meta.Marshal() + assert.NoError(t, err) + expectedPb3 := &BlockMeta{} + err = expectedPb3.Unmarshal(expectedPb) + assert.NoError(t, err) + assert.Equal(t, meta, expectedPb3) + + // Round trip the json expected, err = json.Marshal(meta) assert.NoError(t, err) + expected2 := &BlockMeta{} + err = json.Unmarshal(expected, expected2) + assert.NoError(t, err) + assert.Equal(t, meta, expected2) + + // Write the block meta to the backend and validate the payloads. err = w.WriteBlockMeta(ctx, meta) assert.NoError(t, err) - assert.Equal(t, expected, m.writeBuffer) + assert.Equal(t, expectedPb, m.writeBuffer[len(m.writeBuffer)-2]) + assert.Equal(t, expected, m.writeBuffer[len(m.writeBuffer)-1]) + // Write teh tenant index to the backend and validate the payloads. err = w.WriteTenantIndex(ctx, "test", []*BlockMeta{meta}, nil) assert.NoError(t, err) + idxPb := &TenantIndex{} + err = proto.Unmarshal(m.writeBuffer[len(m.writeBuffer)-2], idxPb) + assert.NoError(t, err) idx := &TenantIndex{} - err = idx.unmarshal(m.writeBuffer) + err = idx.unmarshal(m.writeBuffer[len(m.writeBuffer)-1]) assert.NoError(t, err) assert.True(t, cmp.Equal([]*BlockMeta{meta}, idx.Meta)) // using cmp.Equal to compare json datetimes @@ -58,7 +94,7 @@ func TestWriter(t *testing.T) { err = w.WriteTenantIndex(ctx, "test", nil, nil) assert.NoError(t, err) - expectedDeleteMap := map[string]map[string]int{TenantIndexName: {"test": 1}} + expectedDeleteMap := map[string]map[string]int{TenantIndexName: {"test": 1}, TenantIndexNamePb: {"test": 1}} assert.Equal(t, expectedDeleteMap, w.(*writer).w.(*MockRawWriter).deleteCalls) // When a backend returns ErrDoesNotExist, the tenant index should be deleted, but no error should be returned if the tenant index does not exist diff --git a/tempodb/backend/s3/compactor.go b/tempodb/backend/s3/compactor.go index 21fa37fc323..12793b1c61d 100644 --- a/tempodb/backend/s3/compactor.go +++ b/tempodb/backend/s3/compactor.go @@ -21,11 +21,33 @@ func (rw *readerWriter) MarkBlockCompacted(blockID uuid.UUID, tenantID string) e } putObjectOptions := getPutObjectOptions(rw) + ctx := context.TODO() - metaFileName := backend.MetaFileName(blockID, tenantID, rw.cfg.Prefix) + metaFileNamePb := backend.MetaFileNamePb(blockID, tenantID, rw.cfg.Prefix) // copy meta.json to meta.compacted.json _, err := rw.core.CopyObject( - context.TODO(), + ctx, + rw.cfg.Bucket, + metaFileNamePb, + rw.cfg.Bucket, + backend.CompactedMetaFileNamePb(blockID, tenantID, rw.cfg.Prefix), + nil, + minio.CopySrcOptions{}, + putObjectOptions, + ) + if err != nil { + level.Error(rw.logger).Log("msg", "error copying obj meta.pb to compacted.pb, is this block from previous Tempo version?", "err", err) + } else { + err = rw.core.RemoveObject(ctx, rw.cfg.Bucket, metaFileNamePb, minio.RemoveObjectOptions{}) + if err != nil { + return err + } + } + + metaFileName := backend.MetaFileName(blockID, tenantID, rw.cfg.Prefix) + // copy meta.json to meta.compacted.json + _, err = rw.core.CopyObject( + ctx, rw.cfg.Bucket, metaFileName, rw.cfg.Bucket, @@ -39,7 +61,7 @@ func (rw *readerWriter) MarkBlockCompacted(blockID uuid.UUID, tenantID string) e } // delete meta.json - return rw.core.RemoveObject(context.TODO(), rw.cfg.Bucket, metaFileName, minio.RemoveObjectOptions{}) + return rw.core.RemoveObject(ctx, rw.cfg.Bucket, metaFileName, minio.RemoveObjectOptions{}) } func (rw *readerWriter) ClearBlock(blockID uuid.UUID, tenantID string) error { @@ -78,6 +100,13 @@ func (rw *readerWriter) CompactedBlockMeta(blockID uuid.UUID, tenantID string) ( return nil, backend.ErrEmptyBlockID } + outPb, err := rw.compactedBlockMetaPb(blockID, tenantID) + if err == nil { + return outPb, nil + } + + // TODO: record a note about fallback + compactedMetaFileName := backend.CompactedMetaFileName(blockID, tenantID, rw.cfg.Prefix) bytes, info, err := rw.readAllWithObjInfo(context.TODO(), compactedMetaFileName) if err != nil { @@ -93,3 +122,20 @@ func (rw *readerWriter) CompactedBlockMeta(blockID uuid.UUID, tenantID string) ( return out, nil } + +func (rw *readerWriter) compactedBlockMetaPb(blockID uuid.UUID, tenantID string) (*backend.CompactedBlockMeta, error) { + compactedMetaFileNamePb := backend.CompactedMetaFileNamePb(blockID, tenantID, rw.cfg.Prefix) + bytes, info, err := rw.readAllWithObjInfo(context.TODO(), compactedMetaFileNamePb) + if err != nil { + return nil, readError(err) + } + + out := &backend.CompactedBlockMeta{} + err = out.Unmarshal(bytes) + if err != nil { + return nil, err + } + out.CompactedTime = info.LastModified + + return out, nil +} diff --git a/tempodb/backend/s3/s3.go b/tempodb/backend/s3/s3.go index c434de1339f..31a78304f66 100644 --- a/tempodb/backend/s3/s3.go +++ b/tempodb/backend/s3/s3.go @@ -103,8 +103,6 @@ func internalNew(cfg *Config, confirm bool) (*readerWriter, error) { return nil, fmt.Errorf("config is nil") } - l := log.Logger - core, err := createCore(cfg, false) if err != nil { return nil, fmt.Errorf("unexpected error creating core: %w", err) @@ -124,7 +122,7 @@ func internalNew(cfg *Config, confirm bool) (*readerWriter, error) { } rw := &readerWriter{ - logger: l, + logger: log.Logger, cfg: cfg, core: core, hedgedCore: hedgedCore, diff --git a/tempodb/backend/test/backend_test.go b/tempodb/backend/test/backend_test.go index a2316a6936b..91df61ef29b 100644 --- a/tempodb/backend/test/backend_test.go +++ b/tempodb/backend/test/backend_test.go @@ -16,14 +16,6 @@ func TestFixtures(t *testing.T) { ctx = context.Background() ) - // Create the fixtures, but commit them. - // metas := []*backend.BlockMeta{ - // backend.NewBlockMeta(tenant, uuid.New().UUID, "v1", backend.EncGZIP, "adsf"), - // backend.NewBlockMeta(tenant, uuid.New().UUID, "v2", backend.EncNone, "adsf"), - // backend.NewBlockMeta(tenant, uuid.New().UUID, "v3", backend.EncLZ4_4M, "adsf"), - // backend.NewBlockMeta(tenant, uuid.New().UUID, "v4", backend.EncLZ4_1M, "adsf"), - // } - rr, rw, rc, err := local.New(&local.Config{ Path: "./test-data", }) @@ -34,16 +26,24 @@ func TestFixtures(t *testing.T) { r = backend.NewReader(rr) ) - // err = rc.MarkBlockCompacted(uuid.MustParse("05d4e1b5-bed7-42fe-a392-ca807fdb0214"), tenant) - // assert.NoError(t, err) - _, err = r.TenantIndex(ctx, tenant) assert.NoError(t, err) + // To regenerate the fixtures, uncomment the write path. + // metas := []*backend.BlockMeta{ + // backend.NewBlockMeta(tenant, uuid.New().UUID, "v1", backend.EncGZIP, "adsf"), + // backend.NewBlockMeta(tenant, uuid.New().UUID, "v2", backend.EncNone, "adsf"), + // backend.NewBlockMeta(tenant, uuid.New().UUID, "v3", backend.EncLZ4_4M, "adsf"), + // backend.NewBlockMeta(tenant, uuid.New().UUID, "v4", backend.EncLZ4_1M, "adsf"), + // } + // // for _, meta := range metas { // err = w.WriteBlockMeta(ctx, meta) // require.NoError(t, err) // } + // + // err = rc.MarkBlockCompacted(metas[0].BlockID.UUID, tenant) + // assert.NoError(t, err) listMetas, listCompactedMetas, err := rr.ListBlocks(ctx, tenant) require.NoError(t, err) @@ -72,8 +72,8 @@ func TestFixtures(t *testing.T) { nonZeroMeta(t, blockMetas) nonZeroCompactedMeta(t, compactedBlockMetas) - err = backend.NewWriter(rw).WriteTenantIndex(ctx, tenant, blockMetas, nil) - require.NoError(t, err) + // err = backend.NewWriter(rw).WriteTenantIndex(ctx, tenant, blockMetas, compactedBlockMetas) + // require.NoError(t, err) // for _, meta := range metas { // m, e := r.BlockMeta(ctx, meta.BlockID.UUID, tenant) diff --git a/tempodb/backend/test/benchmark_test.go b/tempodb/backend/test/benchmark_test.go index 93f2bc08f58..ada76b8a941 100644 --- a/tempodb/backend/test/benchmark_test.go +++ b/tempodb/backend/test/benchmark_test.go @@ -52,6 +52,7 @@ func BenchmarkIndexLoad(b *testing.B) { require.NoError(b, err) r := backend.NewReader(rr) + _, _ = r.TenantIndex(ctx, tenant) // read the index once to prime the cache b.ResetTimer() for i := 0; i < b.N; i++ { diff --git a/tempodb/backend/v1.pb.go b/tempodb/backend/v1.pb.go index a687439a04b..828114bafcc 100644 --- a/tempodb/backend/v1.pb.go +++ b/tempodb/backend/v1.pb.go @@ -29,22 +29,23 @@ var _ = time.Kitchen const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type BlockMeta struct { - Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"format"` - BlockID github_com_grafana_tempo_pkg_uuid.UUID `protobuf:"bytes,2,opt,name=block_id,json=blockId,proto3,customtype=github.com/grafana/tempo/pkg/uuid.UUID" json:"blockID"` - TenantID string `protobuf:"bytes,5,opt,name=tenant_id,json=tenantId,proto3" json:"tenantID"` - StartTime time.Time `protobuf:"bytes,6,opt,name=start_time,json=startTime,proto3,stdtime" json:"startTime"` - EndTime time.Time `protobuf:"bytes,7,opt,name=end_time,json=endTime,proto3,stdtime" json:"endTime"` - TotalObjects int32 `protobuf:"varint,8,opt,name=total_objects,json=totalObjects,proto3" json:"totalObjects"` - Size_ uint64 `protobuf:"varint,9,opt,name=size,proto3" json:"size,omitempty"` - CompactionLevel uint32 `protobuf:"varint,10,opt,name=compaction_level,json=compactionLevel,proto3" json:"compactionLevel"` - Encoding Encoding `protobuf:"bytes,11,opt,name=encoding,proto3,customtype=Encoding" json:"encoding"` - IndexPageSize uint32 `protobuf:"varint,12,opt,name=index_page_size,json=indexPageSize,proto3" json:"indexPageSize"` - TotalRecords uint32 `protobuf:"varint,13,opt,name=total_records,json=totalRecords,proto3" json:"totalRecords"` - DataEncoding string `protobuf:"bytes,14,opt,name=data_encoding,json=dataEncoding,proto3" json:"dataEncoding"` - BloomShardCount uint32 `protobuf:"varint,15,opt,name=bloom_shard_count,json=bloomShardCount,proto3" json:"bloomShards"` - FooterSize uint32 `protobuf:"varint,16,opt,name=footer_size,json=footerSize,proto3" json:"footerSize"` - DedicatedColumns DedicatedColumns `protobuf:"bytes,17,opt,name=dedicated_columns,json=dedicatedColumns,proto3,customtype=DedicatedColumns" json:"dedicatedColumns,omitempty"` - ReplicationFactor uint32 `protobuf:"varint,18,opt,name=replication_factor,json=replicationFactor,proto3" json:"replicationFactor,omitempty"` + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"format"` + BlockID github_com_grafana_tempo_pkg_uuid.UUID `protobuf:"bytes,2,opt,name=block_id,json=blockId,proto3,customtype=github.com/grafana/tempo/pkg/uuid.UUID" json:"blockID"` + TenantID string `protobuf:"bytes,5,opt,name=tenant_id,json=tenantId,proto3" json:"tenantID"` + StartTime time.Time `protobuf:"bytes,6,opt,name=start_time,json=startTime,proto3,stdtime" json:"startTime"` + EndTime time.Time `protobuf:"bytes,7,opt,name=end_time,json=endTime,proto3,stdtime" json:"endTime"` + TotalObjects int32 `protobuf:"varint,8,opt,name=total_objects,json=totalObjects,proto3" json:"totalObjects"` + Size_ uint64 `protobuf:"varint,9,opt,name=size,proto3" json:"size,omitempty"` + CompactionLevel uint32 `protobuf:"varint,10,opt,name=compaction_level,json=compactionLevel,proto3" json:"compactionLevel"` + Encoding Encoding `protobuf:"bytes,11,opt,name=encoding,proto3,customtype=Encoding" json:"encoding"` + IndexPageSize uint32 `protobuf:"varint,12,opt,name=index_page_size,json=indexPageSize,proto3" json:"indexPageSize"` + TotalRecords uint32 `protobuf:"varint,13,opt,name=total_records,json=totalRecords,proto3" json:"totalRecords"` + DataEncoding string `protobuf:"bytes,14,opt,name=data_encoding,json=dataEncoding,proto3" json:"dataEncoding"` + BloomShardCount uint32 `protobuf:"varint,15,opt,name=bloom_shard_count,json=bloomShardCount,proto3" json:"bloomShards"` + FooterSize uint32 `protobuf:"varint,16,opt,name=footer_size,json=footerSize,proto3" json:"footerSize"` + DedicatedColumns DedicatedColumns `protobuf:"bytes,17,opt,name=dedicated_columns,json=dedicatedColumns,proto3,customtype=DedicatedColumns" json:"dedicatedColumns,omitempty"` + // repeated bytes dedicated_columns = 17 [(gogoproto.customtype) = "DedicatedColumn", (gogoproto.jsontag) = "dedicatedColumns,omitempty", (gogoproto.nullable) = false]; + ReplicationFactor uint32 `protobuf:"varint,18,opt,name=replication_factor,json=replicationFactor,proto3" json:"replicationFactor,omitempty"` } func (m *BlockMeta) Reset() { *m = BlockMeta{} } diff --git a/tempodb/backend/v1/v1.proto b/tempodb/backend/v1/v1.proto index fe58ea8d555..b6480ba87b7 100644 --- a/tempodb/backend/v1/v1.proto +++ b/tempodb/backend/v1/v1.proto @@ -23,6 +23,7 @@ message BlockMeta { uint32 bloom_shard_count = 15[(gogoproto.jsontag) = "bloomShards"]; uint32 footer_size = 16[(gogoproto.jsontag) = "footerSize"]; bytes dedicated_columns = 17 [(gogoproto.customtype) = "DedicatedColumns", (gogoproto.jsontag) = "dedicatedColumns,omitempty", (gogoproto.nullable) = false]; + // repeated bytes dedicated_columns = 17 [(gogoproto.customtype) = "DedicatedColumn", (gogoproto.jsontag) = "dedicatedColumns,omitempty", (gogoproto.nullable) = false]; uint32 replication_factor = 18[(gogoproto.jsontag) = "replicationFactor,omitempty"]; } From af4b85da5c66dfa704781b2c0e72dd4c32eb45cd Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Fri, 13 Sep 2024 20:56:29 +0000 Subject: [PATCH 36/71] Fix lint --- tempodb/backend/raw_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tempodb/backend/raw_test.go b/tempodb/backend/raw_test.go index 72319d92d46..fc6763b54b1 100644 --- a/tempodb/backend/raw_test.go +++ b/tempodb/backend/raw_test.go @@ -74,7 +74,7 @@ func TestWriter(t *testing.T) { assert.Equal(t, expectedPb, m.writeBuffer[len(m.writeBuffer)-2]) assert.Equal(t, expected, m.writeBuffer[len(m.writeBuffer)-1]) - // Write teh tenant index to the backend and validate the payloads. + // Write the tenant index to the backend and validate the payloads. err = w.WriteTenantIndex(ctx, "test", []*BlockMeta{meta}, nil) assert.NoError(t, err) From fe711692566a1031415baadd04d22cab1da74291 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Mon, 23 Sep 2024 19:21:50 +0000 Subject: [PATCH 37/71] Back UUID with google.UUID to avoid struct --- pkg/uuid/uuid.go | 33 +++++++++++++++------------------ pkg/uuid/uuid_test.go | 10 +++++----- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/pkg/uuid/uuid.go b/pkg/uuid/uuid.go index 90c8d402af5..c9e14ed97fd 100644 --- a/pkg/uuid/uuid.go +++ b/pkg/uuid/uuid.go @@ -14,16 +14,14 @@ var ( _ json.Marshaler = &UUID{} ) -type UUID struct { - google_uuid.UUID -} +type UUID google_uuid.UUID func New() UUID { - return UUID{google_uuid.New()} + return UUID(google_uuid.New()) } func MustParse(s string) UUID { - return UUID{google_uuid.MustParse(s)} + return UUID(google_uuid.MustParse(s)) } func Parse(s string) (UUID, error) { @@ -32,28 +30,27 @@ func Parse(s string) (UUID, error) { return UUID{}, err } - return UUID{u}, nil + return UUID(u), nil } func From(u google_uuid.UUID) UUID { - return UUID{u} + return UUID(u) } -func (u UUID) Marshal() ([]byte, error) { - return u.MarshalBinary() +func (u UUID) String() string { + return ((google_uuid.UUID)(u)).String() } -func (u *UUID) MarshalTo(data []byte) (n int, err error) { - b, err := u.MarshalBinary() - if err != nil { - return 0, err - } +func (u UUID) Marshal() ([]byte, error) { + return ((google_uuid.UUID)(u)).MarshalBinary() +} - return copy(data, b), nil +func (u UUID) MarshalTo(data []byte) (n int, err error) { + return copy(data, u[:]), nil } func (u *UUID) Unmarshal(data []byte) error { - err := u.UnmarshalBinary(data) + err := ((*google_uuid.UUID)(u)).UnmarshalBinary(data) if err != nil { return err } @@ -66,7 +63,7 @@ func (u *UUID) Size() int { } func (u UUID) MarshalJSON() ([]byte, error) { - return json.Marshal(u.String()) + return json.Marshal(((google_uuid.UUID)(u)).String()) } func (u *UUID) UnmarshalJSON(data []byte) error { @@ -81,7 +78,7 @@ func (u *UUID) UnmarshalJSON(data []byte) error { return err } - u.UUID = uu + *u = UUID(uu) return nil } diff --git a/pkg/uuid/uuid_test.go b/pkg/uuid/uuid_test.go index 13f5d7dbf73..58e36945df5 100644 --- a/pkg/uuid/uuid_test.go +++ b/pkg/uuid/uuid_test.go @@ -24,7 +24,7 @@ func Test_roundTrip(t *testing.T) { u2 := UUID{} err = u2.Unmarshal(b) require.NoError(t, err) - assert.Equal(t, u.UUID, u2.UUID) + assert.Equal(t, u, u2) // Marshal b2, err := u2.Marshal() @@ -34,7 +34,7 @@ func Test_roundTrip(t *testing.T) { u3 := UUID{} err = u3.Unmarshal(b2) require.NoError(t, err) - assert.Equal(t, u.UUID, u2.UUID, u3.UUID) + assert.Equal(t, u, u2, u3) // MarshalJSON b3, err := u3.MarshalJSON() @@ -43,17 +43,17 @@ func Test_roundTrip(t *testing.T) { u4 := UUID{} err = u4.UnmarshalJSON(b3) require.NoError(t, err) - assert.Equal(t, u.UUID, u2.UUID, u3.UUID, u4.UUID) + assert.Equal(t, u, u2, u3, u4) } func Test_helpers(t *testing.T) { u := google_uuid.New() s := MustParse(u.String()) - require.Equal(t, u, s.UUID) + require.Equal(t, u, (google_uuid.UUID)(s)) s2, err := Parse(u.String()) require.NoError(t, err) - require.Equal(t, u, s2.UUID) + require.Equal(t, u, (google_uuid.UUID)(s2)) _, err = Parse("x") require.Error(t, err) From d62a3129ac91f6c5f4de82a0b90b0b0650bd7a41 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Mon, 23 Sep 2024 20:20:53 +0000 Subject: [PATCH 38/71] Relocate pkg/uuid to tempodb/backend --- {pkg/uuid => tempodb/backend}/uuid.go | 6 +++--- {pkg/uuid => tempodb/backend}/uuid_test.go | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) rename {pkg/uuid => tempodb/backend}/uuid.go (94%) rename {pkg/uuid => tempodb/backend}/uuid_test.go (91%) diff --git a/pkg/uuid/uuid.go b/tempodb/backend/uuid.go similarity index 94% rename from pkg/uuid/uuid.go rename to tempodb/backend/uuid.go index c9e14ed97fd..e9b91d2bbf4 100644 --- a/pkg/uuid/uuid.go +++ b/tempodb/backend/uuid.go @@ -1,7 +1,7 @@ // Package uuid provides a UUID type that can be used in protocol buffer // messages. It only wraps the google/uuid package and implements a couple // helpers to make creating new instances simpler. -package uuid +package backend import ( "encoding/json" @@ -16,7 +16,7 @@ var ( type UUID google_uuid.UUID -func New() UUID { +func NewUUID() UUID { return UUID(google_uuid.New()) } @@ -24,7 +24,7 @@ func MustParse(s string) UUID { return UUID(google_uuid.MustParse(s)) } -func Parse(s string) (UUID, error) { +func ParseUUID(s string) (UUID, error) { u, err := google_uuid.Parse(s) if err != nil { return UUID{}, err diff --git a/pkg/uuid/uuid_test.go b/tempodb/backend/uuid_test.go similarity index 91% rename from pkg/uuid/uuid_test.go rename to tempodb/backend/uuid_test.go index 58e36945df5..01fbbeb5cc4 100644 --- a/pkg/uuid/uuid_test.go +++ b/tempodb/backend/uuid_test.go @@ -1,4 +1,4 @@ -package uuid +package backend import ( "testing" @@ -9,7 +9,7 @@ import ( ) func Test_roundTrip(t *testing.T) { - u := New() + u := NewUUID() t.Logf("u %x", u) require.Equal(t, 16, u.Size()) @@ -51,10 +51,10 @@ func Test_helpers(t *testing.T) { s := MustParse(u.String()) require.Equal(t, u, (google_uuid.UUID)(s)) - s2, err := Parse(u.String()) + s2, err := ParseUUID(u.String()) require.NoError(t, err) require.Equal(t, u, (google_uuid.UUID)(s2)) - _, err = Parse("x") + _, err = ParseUUID("x") require.Error(t, err) } From 0593a17c292807810e6cd0c53e9e7ebac102a9da Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Mon, 23 Sep 2024 20:31:20 +0000 Subject: [PATCH 39/71] Re-plumb UUID through tempodb --- tempodb/backend/block_meta.go | 9 +- tempodb/backend/block_meta_test.go | 9 +- tempodb/backend/local/local_test.go | 26 +- tempodb/backend/raw.go | 40 +-- tempodb/backend/readerat.go | 5 +- tempodb/backend/test/benchmark_test.go | 3 +- tempodb/backend/uuid.go | 4 - tempodb/backend/v1.pb.go | 132 +++++----- tempodb/backend/v1/v1.proto | 2 +- tempodb/blocklist/list.go | 20 +- tempodb/blocklist/list_test.go | 155 ++++++------ tempodb/blocklist/poller.go | 22 +- tempodb/blocklist/poller_test.go | 87 ++++--- tempodb/compaction_block_selector_test.go | 235 +++++++++--------- tempodb/compactor.go | 5 +- tempodb/compactor_test.go | 21 +- tempodb/encoding/v2/backend_block.go | 3 +- tempodb/encoding/v2/backend_block_test.go | 2 +- tempodb/encoding/v2/block.go | 15 +- tempodb/encoding/v2/create_block.go | 3 +- tempodb/encoding/v2/streaming_block_test.go | 2 +- tempodb/encoding/v2/wal_block.go | 2 +- .../encoding/vparquet2/block_findtracebyid.go | 5 +- tempodb/encoding/vparquet2/compactor.go | 3 +- tempodb/encoding/vparquet2/compactor_test.go | 3 +- tempodb/encoding/vparquet2/copy.go | 13 +- tempodb/encoding/vparquet2/create.go | 6 +- tempodb/encoding/vparquet2/readers.go | 5 +- .../encoding/vparquet3/block_findtracebyid.go | 5 +- tempodb/encoding/vparquet3/compactor.go | 3 +- tempodb/encoding/vparquet3/compactor_test.go | 3 +- tempodb/encoding/vparquet3/copy.go | 13 +- tempodb/encoding/vparquet3/create.go | 6 +- tempodb/encoding/vparquet3/readers.go | 3 +- .../encoding/vparquet4/block_findtracebyid.go | 5 +- tempodb/encoding/vparquet4/compactor.go | 3 +- tempodb/encoding/vparquet4/compactor_test.go | 3 +- tempodb/encoding/vparquet4/copy.go | 13 +- tempodb/encoding/vparquet4/create.go | 6 +- tempodb/encoding/vparquet4/readers.go | 3 +- tempodb/retention.go | 5 +- tempodb/retention_test.go | 12 +- tempodb/tempodb.go | 2 +- tempodb/tempodb_search_test.go | 9 +- tempodb/tempodb_test.go | 121 +++++---- 45 files changed, 523 insertions(+), 529 deletions(-) diff --git a/tempodb/backend/block_meta.go b/tempodb/backend/block_meta.go index bb406d7b93a..78d249aa88e 100644 --- a/tempodb/backend/block_meta.go +++ b/tempodb/backend/block_meta.go @@ -7,11 +7,10 @@ import ( "time" "github.com/cespare/xxhash/v2" - google_uuid "github.com/google/uuid" + "github.com/google/uuid" "github.com/grafana/tempo/pkg/tempopb" "github.com/grafana/tempo/pkg/traceql" - "github.com/grafana/tempo/pkg/uuid" ) // DedicatedColumnType is the type of the values in the dedicated attribute column. Only 'string' is supported. @@ -150,14 +149,14 @@ func (dcs *DedicatedColumns) UnmarshalJSON(b []byte) error { return nil } -func NewBlockMeta(tenantID string, blockID google_uuid.UUID, version string, encoding Encoding, dataEncoding string) *BlockMeta { +func NewBlockMeta(tenantID string, blockID uuid.UUID, version string, encoding Encoding, dataEncoding string) *BlockMeta { return NewBlockMetaWithDedicatedColumns(tenantID, blockID, version, encoding, dataEncoding, nil) } -func NewBlockMetaWithDedicatedColumns(tenantID string, blockID google_uuid.UUID, version string, encoding Encoding, dataEncoding string, dc DedicatedColumns) *BlockMeta { +func NewBlockMetaWithDedicatedColumns(tenantID string, blockID uuid.UUID, version string, encoding Encoding, dataEncoding string, dc DedicatedColumns) *BlockMeta { b := &BlockMeta{ Version: version, - BlockID: uuid.UUID{UUID: blockID}, + BlockID: UUID(blockID), TenantID: tenantID, Encoding: encoding, DataEncoding: dataEncoding, diff --git a/tempodb/backend/block_meta_test.go b/tempodb/backend/block_meta_test.go index a6e7a267da6..11a9b9aaff1 100644 --- a/tempodb/backend/block_meta_test.go +++ b/tempodb/backend/block_meta_test.go @@ -6,12 +6,11 @@ import ( "testing" "time" - google_uuid "github.com/google/uuid" + uuid "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/grafana/tempo/pkg/tempopb" - "github.com/grafana/tempo/pkg/uuid" ) const ( @@ -23,10 +22,10 @@ func TestNewBlockMeta(t *testing.T) { testEncoding := EncLZ4_256k testDataEncoding := "blarg" - id := google_uuid.New() + id := uuid.New() b := NewBlockMeta(testTenantID, id, testVersion, testEncoding, testDataEncoding) - assert.Equal(t, id, b.BlockID.UUID) + assert.Equal(t, id, (uuid.UUID)(b.BlockID)) assert.Equal(t, testTenantID, b.TenantID) assert.Equal(t, testVersion, b.Version) assert.Equal(t, testEncoding, b.Encoding) @@ -100,7 +99,7 @@ func TestBlockMetaParsing(t *testing.T) { meta := BlockMeta{ Version: "vParquet3", - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: MustParse("00000000-0000-0000-0000-000000000000"), TenantID: "single-tenant", StartTime: timeParse("2021-01-01T00:00:00.0000000Z"), EndTime: timeParse("2021-01-02T00:00:00.0000000Z"), diff --git a/tempodb/backend/local/local_test.go b/tempodb/backend/local/local_test.go index 4eb125471cb..8874a60ef43 100644 --- a/tempodb/backend/local/local_test.go +++ b/tempodb/backend/local/local_test.go @@ -9,12 +9,12 @@ import ( "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/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" ) @@ -38,7 +38,7 @@ func TestReadWrite(t *testing.T) { } fakeMeta := &backend.BlockMeta{ - BlockID: blockID, + BlockID: backend.UUID(blockID), } fakeObject := make([]byte, 20) @@ -49,23 +49,23 @@ func TestReadWrite(t *testing.T) { ctx := context.Background() for _, id := range tenantIDs { fakeMeta.TenantID = id - err = w.Write(ctx, objectName, backend.KeyPathForBlock(fakeMeta.BlockID.UUID, id), bytes.NewReader(fakeObject), int64(len(fakeObject)), nil) + 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(fakeMeta.BlockID.UUID, id), bytes.NewReader(fakeObject), int64(len(fakeObject)), nil) + 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(fakeMeta.BlockID.UUID, id), bytes.NewReader(fakeObject), int64(len(fakeObject)), nil) + 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.UUID, tenantIDs[0]), nil) + 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.UUID, tenantIDs[0]), 5, actualReadRange, nil) + 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) @@ -87,12 +87,12 @@ func TestShutdownLeavesTenantsWithBlocks(t *testing.T) { require.NoError(t, err) ctx := context.Background() - blockID := uuid.New() + blockID := backend.NewUUID() contents := bytes.NewReader([]byte("test")) tenant := "fake" // write a "block" - err = w.Write(ctx, "test", backend.KeyPathForBlock(blockID.UUID, tenant), contents, contents.Size(), nil) + err = w.Write(ctx, "test", backend.KeyPathForBlock((uuid.UUID)(blockID), tenant), contents, contents.Size(), nil) require.NoError(t, err) tenantExists(t, tenant, r) @@ -112,19 +112,19 @@ func TestShutdownRemovesTenantsWithoutBlocks(t *testing.T) { require.NoError(t, err) ctx := context.Background() - blockID := uuid.New() + blockID := backend.NewUUID() contents := bytes.NewReader([]byte("test")) tenant := "tenant" // write a "block" - err = w.Write(ctx, "test", backend.KeyPathForBlock(blockID.UUID, tenant), contents, contents.Size(), nil) + 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(blockID.UUID, tenant) + err = c.ClearBlock((uuid.UUID)(blockID), tenant) require.NoError(t, err) tenantExists(t, tenant, r) @@ -150,7 +150,7 @@ func tenantExists(t *testing.T, tenant string, r backend.RawReader) { require.Equal(t, tenant, tenants[0]) } -func blockExists(t *testing.T, blockID uuid.UUID, tenant string, r backend.RawReader) { +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) diff --git a/tempodb/backend/raw.go b/tempodb/backend/raw.go index a3989277dcf..1e0540dc3e5 100644 --- a/tempodb/backend/raw.go +++ b/tempodb/backend/raw.go @@ -10,7 +10,7 @@ import ( "time" proto "github.com/gogo/protobuf/proto" - google_uuid "github.com/google/uuid" + "github.com/google/uuid" tempo_io "github.com/grafana/tempo/pkg/io" ) @@ -61,7 +61,7 @@ type RawReader interface { // List returns all objects one level beneath the provided keypath List(ctx context.Context, keypath KeyPath) ([]string, error) // ListBlocks returns all blockIDs and compactedBlockIDs for a tenant. - ListBlocks(ctx context.Context, tenant string) (blockIDs []google_uuid.UUID, compactedBlockIDs []google_uuid.UUID, err error) + ListBlocks(ctx context.Context, tenant string) (blockIDs []uuid.UUID, compactedBlockIDs []uuid.UUID, err error) // Find executes the FindFunc for each object in the backend starting at the specified keypath. Collection of these objects is the callers responsibility. Find(ctx context.Context, keypath KeyPath, f FindFunc) error // Read is for streaming entire objects from the backend. There will be an attempt to retrieve this from cache if shouldCache is true. @@ -91,19 +91,19 @@ func NewWriter(w RawWriter) Writer { // ) // Write implements backend.Writer -func (w *writer) Write(ctx context.Context, name string, blockID google_uuid.UUID, tenantID string, buffer []byte, cacheInfo *CacheInfo) error { +func (w *writer) Write(ctx context.Context, name string, blockID uuid.UUID, tenantID string, buffer []byte, cacheInfo *CacheInfo) error { return w.w.Write(ctx, name, KeyPathForBlock(blockID, tenantID), bytes.NewReader(buffer), int64(len(buffer)), cacheInfo) } // Write implements backend.Writer -func (w *writer) StreamWriter(ctx context.Context, name string, blockID google_uuid.UUID, tenantID string, data io.Reader, size int64) error { +func (w *writer) StreamWriter(ctx context.Context, name string, blockID uuid.UUID, tenantID string, data io.Reader, size int64) error { return w.w.Write(ctx, name, KeyPathForBlock(blockID, tenantID), data, size, nil) } // Write implements backend.Writer func (w *writer) WriteBlockMeta(ctx context.Context, meta *BlockMeta) error { var ( - blockID = meta.BlockID.UUID + blockID = meta.BlockID tenantID = meta.TenantID ) @@ -113,7 +113,7 @@ func (w *writer) WriteBlockMeta(ctx context.Context, meta *BlockMeta) error { return err } - err = w.w.Write(ctx, MetaNamePb, KeyPathForBlock(blockID, tenantID), bytes.NewReader(mPb), int64(len(mPb)), nil) + err = w.w.Write(ctx, MetaNamePb, KeyPathForBlock((uuid.UUID)(blockID), tenantID), bytes.NewReader(mPb), int64(len(mPb)), nil) if err != nil { return err } @@ -124,11 +124,11 @@ func (w *writer) WriteBlockMeta(ctx context.Context, meta *BlockMeta) error { return err } - return w.w.Write(ctx, MetaName, KeyPathForBlock(blockID, tenantID), bytes.NewReader(bMeta), int64(len(bMeta)), nil) + return w.w.Write(ctx, MetaName, KeyPathForBlock((uuid.UUID)(blockID), tenantID), bytes.NewReader(bMeta), int64(len(bMeta)), nil) } // Write implements backend.Writer -func (w *writer) Append(ctx context.Context, name string, blockID google_uuid.UUID, tenantID string, tracker AppendTracker, buffer []byte) (AppendTracker, error) { +func (w *writer) Append(ctx context.Context, name string, blockID uuid.UUID, tenantID string, tracker AppendTracker, buffer []byte) (AppendTracker, error) { return w.w.Append(ctx, name, KeyPathForBlock(blockID, tenantID), tracker, buffer) } @@ -192,7 +192,7 @@ func NewReader(r RawReader) Reader { } // Read implements backend.Reader -func (r *reader) Read(ctx context.Context, name string, blockID google_uuid.UUID, tenantID string, cacheInfo *CacheInfo) ([]byte, error) { +func (r *reader) Read(ctx context.Context, name string, blockID uuid.UUID, tenantID string, cacheInfo *CacheInfo) ([]byte, error) { objReader, size, err := r.r.Read(ctx, name, KeyPathForBlock(blockID, tenantID), cacheInfo) if err != nil { return nil, err @@ -202,12 +202,12 @@ func (r *reader) Read(ctx context.Context, name string, blockID google_uuid.UUID } // StreamReader implements backend.Reader -func (r *reader) StreamReader(ctx context.Context, name string, blockID google_uuid.UUID, tenantID string) (io.ReadCloser, int64, error) { +func (r *reader) StreamReader(ctx context.Context, name string, blockID uuid.UUID, tenantID string) (io.ReadCloser, int64, error) { return r.r.Read(ctx, name, KeyPathForBlock(blockID, tenantID), nil) } // ReadRange implements backend.Reader -func (r *reader) ReadRange(ctx context.Context, name string, blockID google_uuid.UUID, tenantID string, offset uint64, buffer []byte, cacheInfo *CacheInfo) error { +func (r *reader) ReadRange(ctx context.Context, name string, blockID uuid.UUID, tenantID string, offset uint64, buffer []byte, cacheInfo *CacheInfo) error { return r.r.ReadRange(ctx, name, KeyPathForBlock(blockID, tenantID), offset, buffer, cacheInfo) } @@ -227,12 +227,12 @@ func (r *reader) Tenants(ctx context.Context) ([]string, error) { } // Blocks implements backend.Reader -func (r *reader) Blocks(ctx context.Context, tenantID string) ([]google_uuid.UUID, []google_uuid.UUID, error) { +func (r *reader) Blocks(ctx context.Context, tenantID string) ([]uuid.UUID, []uuid.UUID, error) { return r.r.ListBlocks(ctx, tenantID) } // BlockMeta implements backend.Reader -func (r *reader) BlockMeta(ctx context.Context, blockID google_uuid.UUID, tenantID string) (*BlockMeta, error) { +func (r *reader) BlockMeta(ctx context.Context, blockID uuid.UUID, tenantID string) (*BlockMeta, error) { ctx, span := tracer.Start(ctx, "reader.BlockMeta") defer span.End() @@ -263,7 +263,7 @@ func (r *reader) BlockMeta(ctx context.Context, blockID google_uuid.UUID, tenant return out, nil } -func (r *reader) blockMetaPb(ctx context.Context, blockID google_uuid.UUID, tenantID string) (*BlockMeta, error) { +func (r *reader) blockMetaPb(ctx context.Context, blockID uuid.UUID, tenantID string) (*BlockMeta, error) { // Read proto first, and fall back to json readerPb, size, err := r.r.Read(ctx, MetaNamePb, KeyPathForBlock(blockID, tenantID), nil) if err != nil { @@ -349,7 +349,7 @@ func (r *reader) Shutdown() { } // KeyPathForBlock returns a correctly ordered keypath given a block id and tenantid -func KeyPathForBlock(blockID google_uuid.UUID, tenantID string) KeyPath { +func KeyPathForBlock(blockID uuid.UUID, tenantID string) KeyPath { return []string{tenantID, blockID.String()} } @@ -368,24 +368,24 @@ func KeyPathWithPrefix(keypath KeyPath, prefix string) KeyPath { } // MetaFileName returns the object name for the block meta given a block id and tenantid -func MetaFileName(blockID google_uuid.UUID, tenantID, prefix string) string { +func MetaFileName(blockID uuid.UUID, tenantID, prefix string) string { return path.Join(prefix, tenantID, blockID.String(), MetaName) } -func MetaFileNamePb(blockID google_uuid.UUID, tenantID, prefix string) string { +func MetaFileNamePb(blockID uuid.UUID, tenantID, prefix string) string { return path.Join(prefix, tenantID, blockID.String(), MetaNamePb) } // CompactedMetaFileName returns the object name for the compacted block meta given a block id and tenantid -func CompactedMetaFileName(blockID google_uuid.UUID, tenantID, prefix string) string { +func CompactedMetaFileName(blockID uuid.UUID, tenantID, prefix string) string { return path.Join(prefix, tenantID, blockID.String(), CompactedMetaName) } -func CompactedMetaFileNamePb(blockID google_uuid.UUID, tenantID, prefix string) string { +func CompactedMetaFileNamePb(blockID uuid.UUID, tenantID, prefix string) string { return path.Join(prefix, tenantID, blockID.String(), CompactedMetaNamePb) } // RootPath returns the root path for a block given a block id and tenantid -func RootPath(blockID google_uuid.UUID, tenantID, prefix string) string { +func RootPath(blockID uuid.UUID, tenantID, prefix string) string { return path.Join(prefix, tenantID, blockID.String()) } diff --git a/tempodb/backend/readerat.go b/tempodb/backend/readerat.go index 7d3439c9609..7bcb97ffdaa 100644 --- a/tempodb/backend/readerat.go +++ b/tempodb/backend/readerat.go @@ -4,6 +4,7 @@ import ( "context" "io" + "github.com/google/uuid" "github.com/grafana/tempo/pkg/util" ) @@ -35,13 +36,13 @@ func NewContextReader(meta *BlockMeta, name string, r Reader) ContextReader { // ReadAt implements ContextReader func (b *backendReader) ReadAt(ctx context.Context, p []byte, off int64) (int, error) { - err := b.r.ReadRange(ctx, b.name, b.meta.BlockID.UUID, b.meta.TenantID, uint64(off), p, nil) + err := b.r.ReadRange(ctx, b.name, (uuid.UUID)(b.meta.BlockID), b.meta.TenantID, uint64(off), p, nil) return len(p), err } // ReadAll implements ContextReader func (b *backendReader) ReadAll(ctx context.Context) ([]byte, error) { - return b.r.Read(ctx, b.name, b.meta.BlockID.UUID, b.meta.TenantID, nil) + return b.r.Read(ctx, b.name, (uuid.UUID)(b.meta.BlockID), b.meta.TenantID, nil) } // Reader implements ContextReader diff --git a/tempodb/backend/test/benchmark_test.go b/tempodb/backend/test/benchmark_test.go index ada76b8a941..f6061ebaa34 100644 --- a/tempodb/backend/test/benchmark_test.go +++ b/tempodb/backend/test/benchmark_test.go @@ -5,7 +5,6 @@ import ( "testing" "time" - "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/backend/local" "github.com/stretchr/testify/require" @@ -21,7 +20,7 @@ func BenchmarkIndexLoad(b *testing.B) { for i := range len(blockMeta) { blockMeta[i] = &backend.BlockMeta{ Version: "vParquet3", - BlockID: uuid.New(), + BlockID: backend.NewUUID(), TenantID: tenant, StartTime: time.Now().Add(-50 * time.Minute), EndTime: time.Now().Add(-40 * time.Minute), diff --git a/tempodb/backend/uuid.go b/tempodb/backend/uuid.go index e9b91d2bbf4..5b6da1cddde 100644 --- a/tempodb/backend/uuid.go +++ b/tempodb/backend/uuid.go @@ -33,10 +33,6 @@ func ParseUUID(s string) (UUID, error) { return UUID(u), nil } -func From(u google_uuid.UUID) UUID { - return UUID(u) -} - func (u UUID) String() string { return ((google_uuid.UUID)(u)).String() } diff --git a/tempodb/backend/v1.pb.go b/tempodb/backend/v1.pb.go index 828114bafcc..828bb90307b 100644 --- a/tempodb/backend/v1.pb.go +++ b/tempodb/backend/v1.pb.go @@ -8,7 +8,6 @@ import ( _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" - github_com_grafana_tempo_pkg_uuid "github.com/grafana/tempo/pkg/uuid" _ "google.golang.org/protobuf/types/known/timestamppb" io "io" math "math" @@ -29,21 +28,21 @@ var _ = time.Kitchen const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type BlockMeta struct { - Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"format"` - BlockID github_com_grafana_tempo_pkg_uuid.UUID `protobuf:"bytes,2,opt,name=block_id,json=blockId,proto3,customtype=github.com/grafana/tempo/pkg/uuid.UUID" json:"blockID"` - TenantID string `protobuf:"bytes,5,opt,name=tenant_id,json=tenantId,proto3" json:"tenantID"` - StartTime time.Time `protobuf:"bytes,6,opt,name=start_time,json=startTime,proto3,stdtime" json:"startTime"` - EndTime time.Time `protobuf:"bytes,7,opt,name=end_time,json=endTime,proto3,stdtime" json:"endTime"` - TotalObjects int32 `protobuf:"varint,8,opt,name=total_objects,json=totalObjects,proto3" json:"totalObjects"` - Size_ uint64 `protobuf:"varint,9,opt,name=size,proto3" json:"size,omitempty"` - CompactionLevel uint32 `protobuf:"varint,10,opt,name=compaction_level,json=compactionLevel,proto3" json:"compactionLevel"` - Encoding Encoding `protobuf:"bytes,11,opt,name=encoding,proto3,customtype=Encoding" json:"encoding"` - IndexPageSize uint32 `protobuf:"varint,12,opt,name=index_page_size,json=indexPageSize,proto3" json:"indexPageSize"` - TotalRecords uint32 `protobuf:"varint,13,opt,name=total_records,json=totalRecords,proto3" json:"totalRecords"` - DataEncoding string `protobuf:"bytes,14,opt,name=data_encoding,json=dataEncoding,proto3" json:"dataEncoding"` - BloomShardCount uint32 `protobuf:"varint,15,opt,name=bloom_shard_count,json=bloomShardCount,proto3" json:"bloomShards"` - FooterSize uint32 `protobuf:"varint,16,opt,name=footer_size,json=footerSize,proto3" json:"footerSize"` - DedicatedColumns DedicatedColumns `protobuf:"bytes,17,opt,name=dedicated_columns,json=dedicatedColumns,proto3,customtype=DedicatedColumns" json:"dedicatedColumns,omitempty"` + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"format"` + BlockID UUID `protobuf:"bytes,2,opt,name=block_id,json=blockId,proto3,customtype=UUID" json:"blockID"` + TenantID string `protobuf:"bytes,5,opt,name=tenant_id,json=tenantId,proto3" json:"tenantID"` + StartTime time.Time `protobuf:"bytes,6,opt,name=start_time,json=startTime,proto3,stdtime" json:"startTime"` + EndTime time.Time `protobuf:"bytes,7,opt,name=end_time,json=endTime,proto3,stdtime" json:"endTime"` + TotalObjects int32 `protobuf:"varint,8,opt,name=total_objects,json=totalObjects,proto3" json:"totalObjects"` + Size_ uint64 `protobuf:"varint,9,opt,name=size,proto3" json:"size,omitempty"` + CompactionLevel uint32 `protobuf:"varint,10,opt,name=compaction_level,json=compactionLevel,proto3" json:"compactionLevel"` + Encoding Encoding `protobuf:"bytes,11,opt,name=encoding,proto3,customtype=Encoding" json:"encoding"` + IndexPageSize uint32 `protobuf:"varint,12,opt,name=index_page_size,json=indexPageSize,proto3" json:"indexPageSize"` + TotalRecords uint32 `protobuf:"varint,13,opt,name=total_records,json=totalRecords,proto3" json:"totalRecords"` + DataEncoding string `protobuf:"bytes,14,opt,name=data_encoding,json=dataEncoding,proto3" json:"dataEncoding"` + BloomShardCount uint32 `protobuf:"varint,15,opt,name=bloom_shard_count,json=bloomShardCount,proto3" json:"bloomShards"` + FooterSize uint32 `protobuf:"varint,16,opt,name=footer_size,json=footerSize,proto3" json:"footerSize"` + DedicatedColumns DedicatedColumns `protobuf:"bytes,17,opt,name=dedicated_columns,json=dedicatedColumns,proto3,customtype=DedicatedColumns" json:"dedicatedColumns,omitempty"` // repeated bytes dedicated_columns = 17 [(gogoproto.customtype) = "DedicatedColumn", (gogoproto.jsontag) = "dedicatedColumns,omitempty", (gogoproto.nullable) = false]; ReplicationFactor uint32 `protobuf:"varint,18,opt,name=replication_factor,json=replicationFactor,proto3" json:"replicationFactor,omitempty"` } @@ -286,57 +285,56 @@ func init() { func init() { proto.RegisterFile("tempodb/backend/v1/v1.proto", fileDescriptor_6bc10ae735c1a340) } var fileDescriptor_6bc10ae735c1a340 = []byte{ - // 795 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x55, 0xdd, 0x8a, 0xdb, 0x46, - 0x14, 0xb6, 0x36, 0x9b, 0xb5, 0x3d, 0x5e, 0xaf, 0xed, 0x09, 0x01, 0xd5, 0x01, 0x8f, 0x59, 0x4a, - 0x71, 0x20, 0x95, 0xd8, 0x94, 0x14, 0x4a, 0xa1, 0x50, 0xad, 0x53, 0x48, 0xe9, 0x4f, 0x50, 0x92, - 0x9b, 0x52, 0x10, 0x23, 0xcd, 0x58, 0x51, 0x57, 0xd2, 0x18, 0x69, 0x6c, 0xda, 0x3c, 0x45, 0x9e, - 0xa6, 0xcf, 0x90, 0xcb, 0xed, 0x5d, 0xe9, 0xc5, 0xb4, 0x78, 0xef, 0x44, 0x1f, 0xa2, 0xcc, 0x91, - 0x2c, 0xd9, 0x0e, 0x65, 0x73, 0x77, 0xce, 0xf9, 0xce, 0xdf, 0x77, 0x34, 0x9f, 0x8d, 0x1e, 0x48, - 0x9e, 0x2c, 0x05, 0xf3, 0x6d, 0x9f, 0x06, 0x57, 0x3c, 0x65, 0xf6, 0xfa, 0xc2, 0x5e, 0x5f, 0x58, - 0xcb, 0x4c, 0x48, 0x81, 0x51, 0x15, 0xb4, 0xd6, 0x17, 0x63, 0x12, 0x0a, 0x11, 0xc6, 0xdc, 0x06, - 0xc4, 0x5f, 0x2d, 0x6c, 0x19, 0x25, 0x3c, 0x97, 0x34, 0x59, 0x96, 0xc9, 0xe3, 0x4f, 0xc3, 0x48, - 0xbe, 0x5e, 0xf9, 0x56, 0x20, 0x12, 0x3b, 0x14, 0xa1, 0x68, 0x32, 0xb5, 0x07, 0x0e, 0x58, 0x65, - 0xfa, 0xf9, 0xbf, 0x6d, 0xd4, 0x75, 0x62, 0x11, 0x5c, 0x7d, 0xcf, 0x25, 0xc5, 0x1f, 0xa3, 0xf6, - 0x9a, 0x67, 0x79, 0x24, 0x52, 0xd3, 0x98, 0x1a, 0xb3, 0xae, 0x83, 0x0a, 0x45, 0x4e, 0x16, 0x22, - 0x4b, 0xa8, 0x74, 0xb7, 0x10, 0xf6, 0x50, 0xc7, 0xd7, 0x25, 0x5e, 0xc4, 0xcc, 0xa3, 0xa9, 0x31, - 0x3b, 0x75, 0xe6, 0xef, 0x14, 0x69, 0xfd, 0xa5, 0xc8, 0x27, 0xbb, 0xc3, 0x33, 0xba, 0xa0, 0x29, - 0xb5, 0x81, 0x99, 0xbd, 0xbc, 0x0a, 0xed, 0xd5, 0x2a, 0x62, 0xd6, 0xab, 0x57, 0xcf, 0xe6, 0x1b, - 0x45, 0xda, 0x30, 0xf4, 0xd9, 0xbc, 0x50, 0xa4, 0xed, 0x97, 0xa6, 0x5b, 0x19, 0x0c, 0x3f, 0x41, - 0x5d, 0xc9, 0x53, 0x9a, 0x4a, 0x3d, 0xe1, 0x2e, 0x2c, 0x62, 0x6e, 0x14, 0xe9, 0xbc, 0x84, 0x20, - 0x14, 0x75, 0x64, 0x65, 0xbb, 0x5b, 0x8b, 0xe1, 0xe7, 0x08, 0xe5, 0x92, 0x66, 0xd2, 0xd3, 0x37, - 0x31, 0x4f, 0xa6, 0xc6, 0xac, 0xf7, 0x78, 0x6c, 0x95, 0x07, 0xb3, 0xb6, 0x67, 0xb0, 0x5e, 0x6e, - 0x0f, 0xe6, 0xdc, 0xd7, 0x5b, 0x17, 0x8a, 0x74, 0xa1, 0x4a, 0xc7, 0xdf, 0xfe, 0x4d, 0x0c, 0xb7, - 0x71, 0xf1, 0xb7, 0xa8, 0xc3, 0x53, 0x56, 0xf6, 0x6b, 0xdf, 0xda, 0xef, 0x5e, 0xd5, 0xaf, 0xcd, - 0x53, 0x56, 0x77, 0xdb, 0x3a, 0xf8, 0x09, 0xea, 0x4b, 0x21, 0x69, 0xec, 0x09, 0xff, 0x17, 0x1e, - 0xc8, 0xdc, 0xec, 0x4c, 0x8d, 0xd9, 0x5d, 0x67, 0x58, 0x28, 0x72, 0x0a, 0xc0, 0x8f, 0x65, 0xdc, - 0xdd, 0xf3, 0x30, 0x46, 0xc7, 0x79, 0xf4, 0x86, 0x9b, 0xdd, 0xa9, 0x31, 0x3b, 0x76, 0xc1, 0xc6, - 0x5f, 0xa1, 0x61, 0x20, 0x92, 0x25, 0x0d, 0x64, 0x24, 0x52, 0x2f, 0xe6, 0x6b, 0x1e, 0x9b, 0x68, - 0x6a, 0xcc, 0xfa, 0xce, 0xbd, 0x42, 0x91, 0x41, 0x83, 0x7d, 0xa7, 0x21, 0xf7, 0x30, 0x80, 0x1f, - 0x69, 0x5a, 0x81, 0x60, 0x51, 0x1a, 0x9a, 0x3d, 0xf8, 0x80, 0xc3, 0xea, 0x03, 0x76, 0x9e, 0x56, - 0x71, 0xb7, 0xce, 0xc0, 0x5f, 0xa0, 0x41, 0x94, 0x32, 0xfe, 0xab, 0xb7, 0xa4, 0x21, 0xf7, 0x60, - 0x99, 0x53, 0x18, 0x36, 0x2a, 0x14, 0xe9, 0x03, 0xf4, 0x9c, 0x86, 0xfc, 0x45, 0xf4, 0x86, 0xbb, - 0xfb, 0x6e, 0xc3, 0x39, 0xe3, 0x81, 0xc8, 0x58, 0x6e, 0xf6, 0xa1, 0xb0, 0xe1, 0xec, 0x96, 0x71, - 0x77, 0xcf, 0xd3, 0x65, 0x8c, 0x4a, 0xea, 0xd5, 0x4b, 0x9e, 0xc1, 0x1b, 0x80, 0x32, 0x0d, 0xd4, - 0x4b, 0xee, 0x79, 0xf8, 0x4b, 0x34, 0xf2, 0x63, 0x21, 0x12, 0x2f, 0x7f, 0x4d, 0x33, 0xe6, 0x05, - 0x62, 0x95, 0x4a, 0x73, 0x00, 0x13, 0x07, 0x85, 0x22, 0x3d, 0x00, 0x5f, 0x68, 0x2c, 0x77, 0x07, - 0x8d, 0x73, 0xa9, 0xf3, 0xb0, 0x8d, 0x7a, 0x0b, 0x21, 0x24, 0xcf, 0x4a, 0x86, 0x43, 0x28, 0x3b, - 0x2b, 0x14, 0x41, 0x65, 0x18, 0xe8, 0xed, 0xd8, 0x38, 0x40, 0x23, 0xc6, 0x59, 0x14, 0x50, 0xc9, - 0xf5, 0xac, 0x78, 0x95, 0xa4, 0xb9, 0x39, 0x82, 0x6b, 0x7e, 0x5e, 0x5d, 0x73, 0x38, 0xdf, 0x26, - 0x5c, 0x96, 0x78, 0xa1, 0xc8, 0x98, 0x1d, 0xc4, 0x1e, 0x89, 0x24, 0xd2, 0x1a, 0x91, 0xbf, 0xb9, - 0xc3, 0x43, 0x0c, 0xff, 0x80, 0x70, 0xc6, 0x97, 0xb1, 0x0e, 0xea, 0x4f, 0xbd, 0xa0, 0x81, 0x14, - 0x99, 0x89, 0x61, 0x39, 0x52, 0x28, 0xf2, 0x60, 0x07, 0xfd, 0x06, 0xc0, 0x9d, 0x76, 0xa3, 0xf7, - 0xc0, 0xf3, 0xdf, 0x0d, 0x84, 0x2f, 0xcb, 0xd7, 0xc0, 0x59, 0xa3, 0x7b, 0x07, 0xa1, 0x52, 0xd1, - 0x09, 0x97, 0x14, 0xa4, 0xdf, 0x7b, 0x7c, 0xdf, 0x6a, 0x7e, 0x76, 0xac, 0x3a, 0xd5, 0x39, 0xd5, - 0xdc, 0xae, 0x15, 0x31, 0x0a, 0x45, 0x5a, 0x6e, 0xd7, 0xaf, 0x7b, 0xfc, 0x8c, 0xce, 0x82, 0x6d, - 0xe7, 0x52, 0x31, 0x47, 0xb7, 0x2a, 0xe6, 0xa3, 0x4a, 0x31, 0xfd, 0xba, 0xb2, 0xd6, 0xcd, 0x7e, - 0xe8, 0xfc, 0x0f, 0x03, 0xf5, 0x2a, 0xf9, 0xeb, 0x17, 0xa6, 0xb5, 0x1e, 0x64, 0x1c, 0x6e, 0x4f, - 0x65, 0xb5, 0xf1, 0x07, 0x69, 0xbd, 0xaa, 0xfa, 0x5a, 0x96, 0x5a, 0xaf, 0x5d, 0xfc, 0x10, 0x1d, - 0x03, 0xfb, 0xa3, 0xe9, 0x9d, 0xff, 0x65, 0xef, 0x42, 0x0a, 0x7e, 0xba, 0x4b, 0x15, 0x8a, 0xee, - 0x40, 0xd1, 0x64, 0xb7, 0xe8, 0xfd, 0x33, 0xef, 0x70, 0x82, 0x53, 0x3e, 0x7c, 0xb7, 0x99, 0x18, - 0xd7, 0x9b, 0x89, 0xf1, 0xcf, 0x66, 0x62, 0xbc, 0xbd, 0x99, 0xb4, 0xae, 0x6f, 0x26, 0xad, 0x3f, - 0x6f, 0x26, 0xad, 0x9f, 0x06, 0x07, 0x7f, 0x07, 0xfe, 0x09, 0x50, 0xfa, 0xec, 0xbf, 0x00, 0x00, - 0x00, 0xff, 0xff, 0x21, 0x5d, 0x33, 0x8e, 0x28, 0x06, 0x00, 0x00, + // 778 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0xdd, 0x8a, 0xdb, 0x46, + 0x14, 0xb6, 0x36, 0xce, 0xda, 0x1e, 0xdb, 0x6b, 0x7b, 0x42, 0x40, 0x75, 0xc0, 0x63, 0x4c, 0x2f, + 0x1c, 0x48, 0x65, 0x36, 0x25, 0x85, 0x52, 0x5a, 0xa8, 0x76, 0x53, 0x48, 0xe9, 0x4f, 0x50, 0x92, + 0x9b, 0x52, 0x10, 0x23, 0xcd, 0x58, 0x51, 0x23, 0x69, 0x8c, 0x34, 0x36, 0x6d, 0x9e, 0x22, 0x4f, + 0xd3, 0x67, 0x08, 0xbd, 0xda, 0xde, 0x95, 0x5e, 0x4c, 0x8b, 0xf7, 0x4e, 0x4f, 0x51, 0xe6, 0x48, + 0x96, 0x6c, 0x2f, 0x65, 0x73, 0x77, 0xce, 0xf9, 0xce, 0x77, 0x66, 0xbe, 0xa3, 0xf9, 0x84, 0x1e, + 0x48, 0x1e, 0xaf, 0x04, 0xf3, 0x16, 0x1e, 0xf5, 0xdf, 0xf0, 0x84, 0x2d, 0x36, 0xe7, 0x8b, 0xcd, + 0xb9, 0xb5, 0x4a, 0x85, 0x14, 0x18, 0x95, 0x45, 0x6b, 0x73, 0x3e, 0x26, 0x81, 0x10, 0x41, 0xc4, + 0x17, 0x80, 0x78, 0xeb, 0xe5, 0x42, 0x86, 0x31, 0xcf, 0x24, 0x8d, 0x57, 0x45, 0xf3, 0xf8, 0x93, + 0x20, 0x94, 0xaf, 0xd7, 0x9e, 0xe5, 0x8b, 0x78, 0x11, 0x88, 0x40, 0xd4, 0x9d, 0x3a, 0x83, 0x04, + 0xa2, 0xa2, 0x7d, 0xf6, 0x47, 0x0b, 0x75, 0xec, 0x48, 0xf8, 0x6f, 0xbe, 0xe7, 0x92, 0xe2, 0x8f, + 0x51, 0x6b, 0xc3, 0xd3, 0x2c, 0x14, 0x89, 0x69, 0x4c, 0x8d, 0x79, 0xc7, 0x46, 0xb9, 0x22, 0xa7, + 0x4b, 0x91, 0xc6, 0x54, 0x3a, 0x3b, 0x08, 0x7f, 0x89, 0xda, 0x9e, 0xa6, 0xb8, 0x21, 0x33, 0x4f, + 0xa6, 0xc6, 0xbc, 0x67, 0xcf, 0xde, 0x2b, 0xd2, 0xf8, 0x5b, 0x91, 0xe6, 0xab, 0x57, 0xcf, 0x2e, + 0xb7, 0x8a, 0xb4, 0x60, 0xe4, 0xb3, 0xcb, 0x5c, 0x91, 0x96, 0x57, 0x84, 0x4e, 0x19, 0x30, 0xfc, + 0x04, 0x75, 0x24, 0x4f, 0x68, 0x22, 0x35, 0xff, 0x2e, 0x1c, 0x63, 0x6e, 0x15, 0x69, 0xbf, 0x84, + 0x22, 0x90, 0xda, 0xb2, 0x8c, 0x9d, 0x5d, 0xc4, 0xf0, 0x73, 0x84, 0x32, 0x49, 0x53, 0xe9, 0x6a, + 0xc5, 0xe6, 0xe9, 0xd4, 0x98, 0x77, 0x1f, 0x8f, 0xad, 0x62, 0x1d, 0xd6, 0x4e, 0xa4, 0xf5, 0x72, + 0xb7, 0x0e, 0xfb, 0xbe, 0xbe, 0x53, 0xae, 0x48, 0x07, 0x58, 0xba, 0xfe, 0xee, 0x1f, 0x62, 0x38, + 0x75, 0x8a, 0xbf, 0x45, 0x6d, 0x9e, 0xb0, 0x62, 0x5e, 0xeb, 0xd6, 0x79, 0xf7, 0xca, 0x79, 0x2d, + 0x9e, 0xb0, 0x6a, 0xda, 0x2e, 0xc1, 0x4f, 0x50, 0x5f, 0x0a, 0x49, 0x23, 0x57, 0x78, 0xbf, 0x70, + 0x5f, 0x66, 0x66, 0x7b, 0x6a, 0xcc, 0xef, 0xda, 0xc3, 0x5c, 0x91, 0x1e, 0x00, 0x3f, 0x16, 0x75, + 0xe7, 0x20, 0xc3, 0x18, 0x35, 0xb3, 0xf0, 0x2d, 0x37, 0x3b, 0x53, 0x63, 0xde, 0x74, 0x20, 0xc6, + 0x5f, 0xa1, 0xa1, 0x2f, 0xe2, 0x15, 0xf5, 0x65, 0x28, 0x12, 0x37, 0xe2, 0x1b, 0x1e, 0x99, 0x68, + 0x6a, 0xcc, 0xfb, 0xf6, 0xbd, 0x5c, 0x91, 0x41, 0x8d, 0x7d, 0xa7, 0x21, 0xe7, 0xb8, 0x80, 0x1f, + 0x69, 0x59, 0xbe, 0x60, 0x61, 0x12, 0x98, 0x5d, 0xf8, 0x3c, 0xc3, 0xf2, 0xf3, 0xb4, 0x9f, 0x96, + 0x75, 0xa7, 0xea, 0xc0, 0x9f, 0xa3, 0x41, 0x98, 0x30, 0xfe, 0xab, 0xbb, 0xa2, 0x01, 0x77, 0xe1, + 0x32, 0x3d, 0x38, 0x6c, 0x94, 0x2b, 0xd2, 0x07, 0xe8, 0x39, 0x0d, 0xf8, 0x8b, 0xf0, 0x2d, 0x77, + 0x0e, 0xd3, 0x5a, 0x73, 0xca, 0x7d, 0x91, 0xb2, 0xcc, 0xec, 0x03, 0xb1, 0xd6, 0xec, 0x14, 0x75, + 0xe7, 0x20, 0xd3, 0x34, 0x46, 0x25, 0x75, 0xab, 0x4b, 0x9e, 0xc1, 0x1b, 0x00, 0x9a, 0x06, 0xaa, + 0x4b, 0x1e, 0x64, 0xf8, 0x0b, 0x34, 0xf2, 0x22, 0x21, 0x62, 0x37, 0x7b, 0x4d, 0x53, 0xe6, 0xfa, + 0x62, 0x9d, 0x48, 0x73, 0x00, 0x27, 0x0e, 0x72, 0x45, 0xba, 0x00, 0xbe, 0xd0, 0x58, 0xe6, 0x0c, + 0xea, 0xe4, 0x42, 0xf7, 0xe1, 0x05, 0xea, 0x2e, 0x85, 0x90, 0x3c, 0x2d, 0x14, 0x0e, 0x81, 0x76, + 0x96, 0x2b, 0x82, 0x8a, 0x32, 0xc8, 0xdb, 0x8b, 0xb1, 0x8f, 0x46, 0x8c, 0xb3, 0xd0, 0xa7, 0x92, + 0xeb, 0xb3, 0xa2, 0x75, 0x9c, 0x64, 0xe6, 0x08, 0xb6, 0xf9, 0x59, 0xb9, 0xcd, 0xe1, 0xe5, 0xae, + 0xe1, 0xa2, 0xc0, 0x73, 0x45, 0xc6, 0xec, 0xa8, 0xf6, 0x48, 0xc4, 0xa1, 0xf6, 0xb6, 0xfc, 0xcd, + 0x19, 0x1e, 0x63, 0xf8, 0x07, 0x84, 0x53, 0xbe, 0x8a, 0x74, 0x51, 0x7f, 0xea, 0x25, 0xf5, 0xa5, + 0x48, 0x4d, 0x0c, 0x97, 0x23, 0xb9, 0x22, 0x0f, 0xf6, 0xd0, 0x6f, 0x00, 0xdc, 0x1b, 0x37, 0xba, + 0x01, 0xce, 0x7e, 0x37, 0x10, 0xbe, 0x28, 0x5e, 0x03, 0x67, 0xb5, 0xab, 0x6d, 0x84, 0x0a, 0xbf, + 0xc6, 0x5c, 0x52, 0x30, 0x76, 0xf7, 0xf1, 0x7d, 0xab, 0xfe, 0xa9, 0x58, 0x55, 0xab, 0xdd, 0xd3, + 0xda, 0xae, 0x14, 0x31, 0x72, 0x45, 0x1a, 0x4e, 0xc7, 0xab, 0x66, 0xfc, 0x8c, 0xce, 0xfc, 0xdd, + 0xe4, 0xc2, 0x31, 0x27, 0xb7, 0x3a, 0xe6, 0xa3, 0xd2, 0x31, 0xfd, 0x8a, 0x59, 0xf9, 0xe6, 0xb0, + 0x34, 0xfb, 0xd3, 0x40, 0xdd, 0xd2, 0xfe, 0xfa, 0x85, 0x69, 0xaf, 0xfb, 0x29, 0x87, 0xdd, 0x53, + 0x59, 0xde, 0xf8, 0x83, 0xbc, 0x5e, 0xb2, 0xbe, 0x96, 0x85, 0xd7, 0xab, 0x14, 0x3f, 0x44, 0x4d, + 0x50, 0x7f, 0x32, 0xbd, 0xf3, 0xbf, 0xea, 0x1d, 0x68, 0xc1, 0x4f, 0xf7, 0xa5, 0x02, 0xe9, 0x0e, + 0x90, 0x26, 0xfb, 0xa4, 0x9b, 0x6b, 0xde, 0xd3, 0x04, 0xab, 0x7c, 0xf8, 0x7e, 0x3b, 0x31, 0xae, + 0xb6, 0x13, 0xe3, 0xdf, 0xed, 0xc4, 0x78, 0x77, 0x3d, 0x69, 0x5c, 0x5d, 0x4f, 0x1a, 0x7f, 0x5d, + 0x4f, 0x1a, 0x3f, 0x0d, 0x8e, 0x7e, 0xf6, 0xde, 0x29, 0x48, 0xfa, 0xf4, 0xbf, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x3f, 0xb9, 0xc7, 0xff, 0x06, 0x06, 0x00, 0x00, } func (m *BlockMeta) Marshal() (dAtA []byte, err error) { diff --git a/tempodb/backend/v1/v1.proto b/tempodb/backend/v1/v1.proto index b6480ba87b7..3f5b42824b3 100644 --- a/tempodb/backend/v1/v1.proto +++ b/tempodb/backend/v1/v1.proto @@ -9,7 +9,7 @@ option go_package = "tempodb/backend"; message BlockMeta { string version = 1[(gogoproto.jsontag) = "format"]; - bytes block_id = 2[(gogoproto.jsontag) = "blockID", (gogoproto.customname) = "BlockID", (gogoproto.customtype) = "github.com/grafana/tempo/pkg/uuid.UUID", (gogoproto.nullable) = false]; + bytes block_id = 2[(gogoproto.jsontag) = "blockID", (gogoproto.customname) = "BlockID", (gogoproto.customtype) = "UUID", (gogoproto.nullable) = false]; string tenant_id = 5[(gogoproto.jsontag) = "tenantID", (gogoproto.customname) = "TenantID"]; google.protobuf.Timestamp start_time = 6[(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = "startTime"]; google.protobuf.Timestamp end_time = 7[(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = "endTime"]; diff --git a/tempodb/blocklist/list.go b/tempodb/blocklist/list.go index 073a0511161..9514ba5bfa0 100644 --- a/tempodb/blocklist/list.go +++ b/tempodb/blocklist/list.go @@ -131,8 +131,8 @@ func (l *List) updateInternal(tenantID string, add []*backend.BlockMeta, remove matchedRemovals := make(map[uuid.UUID]struct{}) for _, b := range blocklist { for _, rem := range remove { - if b.BlockID.UUID == rem.BlockID.UUID { - matchedRemovals[rem.BlockID.UUID] = struct{}{} + if b.BlockID == rem.BlockID { + matchedRemovals[(uuid.UUID)(rem.BlockID)] = struct{}{} break } } @@ -142,14 +142,14 @@ func (l *List) updateInternal(tenantID string, add []*backend.BlockMeta, remove newblocklist := make([]*backend.BlockMeta, 0, len(blocklist)-len(matchedRemovals)+len(add)) // rebuild the blocklist dropping all removals for _, b := range blocklist { - existingMetas[b.BlockID.UUID] = struct{}{} - if _, ok := matchedRemovals[b.BlockID.UUID]; !ok { + existingMetas[(uuid.UUID)(b.BlockID)] = struct{}{} + if _, ok := matchedRemovals[(uuid.UUID)(b.BlockID)]; !ok { newblocklist = append(newblocklist, b) } } // add new blocks (only if they don't already exist) for _, b := range add { - if _, ok := existingMetas[b.BlockID.UUID]; !ok { + if _, ok := existingMetas[(uuid.UUID)(b.BlockID)]; !ok { newblocklist = append(newblocklist, b) } } @@ -162,8 +162,8 @@ func (l *List) updateInternal(tenantID string, add []*backend.BlockMeta, remove compactedRemovals := map[uuid.UUID]struct{}{} for _, c := range compactedBlocklist { for _, rem := range compactedRemove { - if c.BlockID.UUID == rem.BlockID.UUID { - compactedRemovals[rem.BlockID.UUID] = struct{}{} + if c.BlockID == rem.BlockID { + compactedRemovals[(uuid.UUID)(rem.BlockID)] = struct{}{} break } } @@ -173,13 +173,13 @@ func (l *List) updateInternal(tenantID string, add []*backend.BlockMeta, remove newCompactedBlocklist := make([]*backend.CompactedBlockMeta, 0, len(compactedBlocklist)-len(compactedRemovals)+len(compactedAdd)) // rebuild the blocklist dropping all removals for _, b := range compactedBlocklist { - existingMetas[b.BlockID.UUID] = struct{}{} - if _, ok := compactedRemovals[b.BlockID.UUID]; !ok { + existingMetas[(uuid.UUID)(b.BlockID)] = struct{}{} + if _, ok := compactedRemovals[(uuid.UUID)(b.BlockID)]; !ok { newCompactedBlocklist = append(newCompactedBlocklist, b) } } for _, b := range compactedAdd { - if _, ok := existingMetas[b.BlockID.UUID]; !ok { + if _, ok := existingMetas[(uuid.UUID)(b.BlockID)]; !ok { newCompactedBlocklist = append(newCompactedBlocklist, b) } } diff --git a/tempodb/blocklist/list_test.go b/tempodb/blocklist/list_test.go index 263bc9d3a59..0bfa3250ff9 100644 --- a/tempodb/blocklist/list_test.go +++ b/tempodb/blocklist/list_test.go @@ -4,11 +4,10 @@ import ( "sort" "testing" - google_uuid "github.com/google/uuid" + "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" ) @@ -30,12 +29,12 @@ func TestApplyPollResults(t *testing.T) { metas: PerTenant{ "test": []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, }, "test2": []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, }, }, @@ -47,19 +46,19 @@ func TestApplyPollResults(t *testing.T) { "test": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, }, }, "test2": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, }, { BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), }, }, }, @@ -71,12 +70,12 @@ func TestApplyPollResults(t *testing.T) { metas: PerTenant{ "test": []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, }, "blerg": []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, }, }, @@ -84,19 +83,19 @@ func TestApplyPollResults(t *testing.T) { "test": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, }, }, "test2": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, }, { BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), }, }, }, @@ -145,13 +144,13 @@ func TestUpdate(t *testing.T) { existing: nil, add: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, }, remove: nil, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, }, }, @@ -159,21 +158,21 @@ func TestUpdate(t *testing.T) { name: "add to existing", existing: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, }, add: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), }, }, remove: nil, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), }, }, }, @@ -183,7 +182,7 @@ func TestUpdate(t *testing.T) { add: nil, remove: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), }, }, expected: nil, @@ -192,14 +191,14 @@ func TestUpdate(t *testing.T) { name: "remove nil", existing: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), }, }, add: nil, remove: nil, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), }, }, }, @@ -207,21 +206,21 @@ func TestUpdate(t *testing.T) { name: "remove existing", existing: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), }, }, add: nil, remove: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), }, }, }, @@ -229,18 +228,18 @@ func TestUpdate(t *testing.T) { name: "remove no match", existing: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, }, add: nil, remove: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, }, }, @@ -248,28 +247,28 @@ func TestUpdate(t *testing.T) { name: "add and remove", existing: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), }, }, add: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000003"), }, }, remove: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000003"), }, }, }, @@ -277,24 +276,24 @@ func TestUpdate(t *testing.T) { name: "add already exists", existing: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, }, add: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), }, }, remove: nil, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), }, }, }, @@ -336,14 +335,14 @@ func TestUpdateCompacted(t *testing.T) { add: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, }, }, expected: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, }, }, @@ -353,26 +352,26 @@ func TestUpdateCompacted(t *testing.T) { existing: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, }, }, add: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), }, }, }, expected: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, }, { BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), }, }, }, @@ -382,31 +381,31 @@ func TestUpdateCompacted(t *testing.T) { existing: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, }, }, add: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, }, { BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), }, }, }, expected: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, }, { BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), }, }, }, @@ -416,38 +415,38 @@ func TestUpdateCompacted(t *testing.T) { existing: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, }, { BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), }, }, }, add: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000003"), }, }, }, remove: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), }, }, }, expected: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, }, { BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000003"), }, }, }, @@ -474,10 +473,10 @@ func TestUpdatesSaved(t *testing.T) { // unlike most tests these are applied serially to the same list object and the expected // results are cumulative across all tests - one := google_uuid.MustParse("00000000-0000-0000-0000-000000000001") - two := google_uuid.MustParse("00000000-0000-0000-0000-000000000002") - oneOhOne := google_uuid.MustParse("10000000-0000-0000-0000-000000000001") - oneOhTwo := google_uuid.MustParse("10000000-0000-0000-0000-000000000002") + one := uuid.MustParse("00000000-0000-0000-0000-000000000001") + two := uuid.MustParse("00000000-0000-0000-0000-000000000002") + oneOhOne := uuid.MustParse("10000000-0000-0000-0000-000000000001") + oneOhTwo := uuid.MustParse("10000000-0000-0000-0000-000000000002") tests := []struct { applyMetas PerTenant @@ -496,7 +495,7 @@ func TestUpdatesSaved(t *testing.T) { applyMetas: PerTenant{ "test": []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: one}, + BlockID: backend.UUID(one), }, }, }, @@ -504,7 +503,7 @@ func TestUpdatesSaved(t *testing.T) { "test": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: oneOhOne}, + BlockID: backend.UUID(oneOhOne), }, }, }, @@ -512,21 +511,21 @@ func TestUpdatesSaved(t *testing.T) { updateTenant: "test", addMetas: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: one}, + BlockID: backend.UUID(one), }, { - BlockID: uuid.UUID{UUID: two}, + BlockID: backend.UUID(two), }, }, removeMetas: []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: one}, + BlockID: backend.UUID(one), }, }, addCompacted: []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: oneOhTwo}, + BlockID: backend.UUID(oneOhTwo), }, }, }, @@ -534,7 +533,7 @@ func TestUpdatesSaved(t *testing.T) { expectedMetas: PerTenant{ "test": []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: two}, + BlockID: backend.UUID(two), }, }, }, @@ -542,12 +541,12 @@ func TestUpdatesSaved(t *testing.T) { "test": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: oneOhOne}, + BlockID: backend.UUID(oneOhOne), }, }, { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: oneOhTwo}, + BlockID: backend.UUID(oneOhTwo), }, }, }, @@ -558,7 +557,7 @@ func TestUpdatesSaved(t *testing.T) { applyMetas: PerTenant{ "test": []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: one}, + BlockID: backend.UUID(one), }, }, }, @@ -566,7 +565,7 @@ func TestUpdatesSaved(t *testing.T) { "test": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: oneOhOne}, + BlockID: backend.UUID(oneOhOne), }, }, }, @@ -579,7 +578,7 @@ func TestUpdatesSaved(t *testing.T) { // BlockID: one, // }, { - BlockID: uuid.UUID{UUID: two}, + BlockID: backend.UUID(two), }, }, }, @@ -587,12 +586,12 @@ func TestUpdatesSaved(t *testing.T) { "test": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: oneOhOne}, + BlockID: backend.UUID(oneOhOne), }, }, { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: oneOhTwo}, + BlockID: backend.UUID(oneOhTwo), }, }, }, @@ -603,7 +602,7 @@ func TestUpdatesSaved(t *testing.T) { applyMetas: PerTenant{ "test": []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: one}, + BlockID: backend.UUID(one), }, }, }, @@ -611,7 +610,7 @@ func TestUpdatesSaved(t *testing.T) { "test": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: oneOhOne}, + BlockID: backend.UUID(oneOhOne), }, }, }, @@ -620,7 +619,7 @@ func TestUpdatesSaved(t *testing.T) { expectedMetas: PerTenant{ "test": []*backend.BlockMeta{ { - BlockID: uuid.UUID{UUID: one}, + BlockID: backend.UUID(one), }, }, }, @@ -628,7 +627,7 @@ func TestUpdatesSaved(t *testing.T) { "test": []*backend.CompactedBlockMeta{ { BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{UUID: oneOhOne}, + BlockID: backend.UUID(oneOhOne), }, }, }, diff --git a/tempodb/blocklist/poller.go b/tempodb/blocklist/poller.go index ead5e9aa14b..4f0e5207b36 100644 --- a/tempodb/blocklist/poller.go +++ b/tempodb/blocklist/poller.go @@ -13,7 +13,7 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" - google_uuid "github.com/google/uuid" + uuid "github.com/google/uuid" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "go.opentelemetry.io/otel" @@ -320,28 +320,28 @@ func (p *Poller) pollTenantBlocks( var ( metas = previous.Metas(tenantID) compactedMetas = previous.CompactedMetas(tenantID) - mm = make(map[google_uuid.UUID]*backend.BlockMeta, len(metas)) - cm = make(map[google_uuid.UUID]*backend.CompactedBlockMeta, len(compactedMetas)) + mm = make(map[backend.UUID]*backend.BlockMeta, len(metas)) + cm = make(map[backend.UUID]*backend.CompactedBlockMeta, len(compactedMetas)) newBlockList = make([]*backend.BlockMeta, 0, len(currentBlockIDs)) newCompactedBlocklist = make([]*backend.CompactedBlockMeta, 0, len(currentCompactedBlockIDs)) - unknownBlockIDs = make(map[google_uuid.UUID]bool, 1000) + unknownBlockIDs = make(map[uuid.UUID]bool, 1000) ) span.SetAttributes(attribute.Int("metas", len(metas))) span.SetAttributes(attribute.Int("compactedMetas", len(compactedMetas))) for _, i := range metas { - mm[i.BlockID.UUID] = i + mm[i.BlockID] = i } for _, i := range compactedMetas { - cm[i.BlockID.UUID] = i + cm[i.BlockID] = i } // The boolean here to track if we know the block has been compacted for _, blockID := range currentBlockIDs { // if we already have this block id in our previous list, use the existing data. - if v, ok := mm[blockID]; ok { + if v, ok := mm[backend.UUID(blockID)]; ok { newBlockList = append(newBlockList, v) continue } @@ -351,7 +351,7 @@ func (p *Poller) pollTenantBlocks( for _, blockID := range currentCompactedBlockIDs { // if we already have this block id in our previous list, use the existing data. - if v, ok := cm[blockID]; ok { + if v, ok := cm[backend.UUID(blockID)]; ok { newCompactedBlocklist = append(newCompactedBlocklist, v) continue } @@ -385,7 +385,7 @@ func (p *Poller) pollTenantBlocks( func (p *Poller) pollUnknown( ctx context.Context, - unknownBlocks map[google_uuid.UUID]bool, + unknownBlocks map[uuid.UUID]bool, tenantID string, ) ([]*backend.BlockMeta, []*backend.CompactedBlockMeta, error) { derivedCtx, span := tracer.Start(ctx, "pollUnknown", trace.WithAttributes( @@ -412,7 +412,7 @@ func (p *Poller) pollUnknown( mtx.Unlock() bg.Add(1) - go func(id google_uuid.UUID, compacted bool) { + go func(id uuid.UUID, compacted bool) { defer bg.Done() if p.cfg.PollJitterMs > 0 { @@ -455,7 +455,7 @@ func (p *Poller) pollUnknown( func (p *Poller) pollBlock( ctx context.Context, tenantID string, - blockID google_uuid.UUID, + blockID uuid.UUID, compacted bool, ) (*backend.BlockMeta, *backend.CompactedBlockMeta, error) { derivedCtx, span := tracer.Start(ctx, "Poller.pollBlock") diff --git a/tempodb/blocklist/poller_test.go b/tempodb/blocklist/poller_test.go index e8c8f9fdfd0..d96f552a417 100644 --- a/tempodb/blocklist/poller_test.go +++ b/tempodb/blocklist/poller_test.go @@ -14,11 +14,10 @@ import ( "time" "github.com/go-kit/log" - google_uuid "github.com/google/uuid" + uuid "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" ) @@ -38,9 +37,9 @@ func (m *mockJobSharder) Owns(_ string) bool { return m.owns } func TestTenantIndexBuilder(t *testing.T) { var ( - one = uuid.MustParse("00000000-0000-0000-0000-000000000001") - two = uuid.MustParse("00000000-0000-0000-0000-000000000002") - three = uuid.MustParse("00000000-0000-0000-0000-000000000003") + one = backend.MustParse("00000000-0000-0000-0000-000000000001") + two = backend.MustParse("00000000-0000-0000-0000-000000000002") + three = backend.MustParse("00000000-0000-0000-0000-000000000003") ) tests := []struct { @@ -290,14 +289,14 @@ func TestTenantIndexFallback(t *testing.T) { } func TestPollBlock(t *testing.T) { - one := uuid.MustParse("00000000-0000-0000-0000-000000000001") + one := backend.MustParse("00000000-0000-0000-0000-000000000001") tests := []struct { name string list PerTenant compactedList PerTenantCompacted pollTenantID string - pollBlockID uuid.UUID + pollBlockID backend.UUID expectedMeta *backend.BlockMeta expectedCompactedMeta *backend.CompactedBlockMeta expectsError bool @@ -370,7 +369,7 @@ func TestPollBlock(t *testing.T) { PollFallback: testPollFallback, TenantIndexBuilders: testBuilders, }, &mockJobSharder{}, r, c, w, log.NewNopLogger()) - actualMeta, actualCompactedMeta, err := poller.pollBlock(context.Background(), tc.pollTenantID, tc.pollBlockID.UUID, false) + actualMeta, actualCompactedMeta, err := poller.pollBlock(context.Background(), tc.pollTenantID, (uuid.UUID)(tc.pollBlockID), false) assert.Equal(t, tc.expectedMeta, actualMeta) assert.Equal(t, tc.expectedCompactedMeta, actualCompactedMeta) @@ -607,7 +606,7 @@ func TestPollTolerateConsecutiveErrors(t *testing.T) { // This mock reader returns error or nil based on the tenant ID r := &backend.MockReader{ - BlocksFn: func(_ context.Context, tenantID string) ([]google_uuid.UUID, []google_uuid.UUID, error) { + BlocksFn: func(_ context.Context, tenantID string) ([]uuid.UUID, []uuid.UUID, error) { mtx.Lock() defer func() { callCounter[tenantID]++ @@ -659,9 +658,9 @@ func TestPollTolerateConsecutiveErrors(t *testing.T) { } func TestPollComparePreviousResults(t *testing.T) { - zero := uuid.MustParse("00000000-0000-0000-0000-000000000000") - aaa := uuid.MustParse("00000000-0000-0000-0000-00000000000A") - eff := uuid.MustParse("00000000-0000-0000-0000-00000000000F") + zero := backend.MustParse("00000000-0000-0000-0000-000000000000") + aaa := backend.MustParse("00000000-0000-0000-0000-00000000000A") + eff := backend.MustParse("00000000-0000-0000-0000-00000000000F") testCases := []struct { name string @@ -675,8 +674,8 @@ func TestPollComparePreviousResults(t *testing.T) { expectedPerTenant PerTenant expectedCompactedPerTenant PerTenantCompacted - expectedBlockMetaCalls map[string]map[google_uuid.UUID]int - expectedCompactedBlockMetaCalls map[string]map[google_uuid.UUID]int + expectedBlockMetaCalls map[string]map[uuid.UUID]int + expectedCompactedBlockMetaCalls map[string]map[uuid.UUID]int tollerateErrors int tollerateTenantFailures int @@ -708,14 +707,14 @@ func TestPollComparePreviousResults(t *testing.T) { {BlockMeta: backend.BlockMeta{BlockID: eff}}, }, }, - expectedBlockMetaCalls: map[string]map[google_uuid.UUID]int{ + expectedBlockMetaCalls: map[string]map[uuid.UUID]int{ "test": { - zero.UUID: 1, + (uuid.UUID)(zero): 1, }, }, - expectedCompactedBlockMetaCalls: map[string]map[google_uuid.UUID]int{ + expectedCompactedBlockMetaCalls: map[string]map[uuid.UUID]int{ "test": { - eff.UUID: 1, + (uuid.UUID)(eff): 1, }, }, }, @@ -744,7 +743,7 @@ func TestPollComparePreviousResults(t *testing.T) { expectedCompactedPerTenant: PerTenantCompacted{ "test": []*backend.CompactedBlockMeta{}, }, - expectedBlockMetaCalls: map[string]map[google_uuid.UUID]int{}, + expectedBlockMetaCalls: map[string]map[uuid.UUID]int{}, }, { name: "with previous results, blocks that have been compacted since the last poll should be known as compacted", @@ -777,15 +776,15 @@ func TestPollComparePreviousResults(t *testing.T) { {BlockMeta: backend.BlockMeta{BlockID: zero}}, }, }, - expectedBlockMetaCalls: map[string]map[google_uuid.UUID]int{ + expectedBlockMetaCalls: map[string]map[uuid.UUID]int{ "test": { - eff.UUID: 1, + (uuid.UUID)(eff): 1, }, }, - expectedCompactedBlockMetaCalls: map[string]map[google_uuid.UUID]int{ + expectedCompactedBlockMetaCalls: map[string]map[uuid.UUID]int{ "test": { - aaa.UUID: 1, - zero.UUID: 1, + (uuid.UUID)(aaa): 1, + (uuid.UUID)(zero): 1, }, }, }, @@ -817,7 +816,7 @@ func TestPollComparePreviousResults(t *testing.T) { {BlockMeta: backend.BlockMeta{BlockID: eff}}, }, }, - expectedBlockMetaCalls: map[string]map[google_uuid.UUID]int{}, + expectedBlockMetaCalls: map[string]map[uuid.UUID]int{}, }, { name: "with previous compactions removed, should be forgotten", @@ -831,7 +830,7 @@ func TestPollComparePreviousResults(t *testing.T) { currentCompactedPerTenant: PerTenantCompacted{}, expectedPerTenant: PerTenant{}, expectedCompactedPerTenant: PerTenantCompacted{}, - expectedBlockMetaCalls: map[string]map[google_uuid.UUID]int{}, + expectedBlockMetaCalls: map[string]map[uuid.UUID]int{}, }, { name: "previous results with read error should maintain previous results", @@ -864,7 +863,7 @@ func TestPollComparePreviousResults(t *testing.T) { {BlockMeta: backend.BlockMeta{BlockID: eff}}, }, }, - expectedBlockMetaCalls: map[string]map[google_uuid.UUID]int{}, + expectedBlockMetaCalls: map[string]map[uuid.UUID]int{}, }, { name: "previous results with read error should maintain previous results when tolerations are low and multiple tenants", @@ -912,7 +911,7 @@ func TestPollComparePreviousResults(t *testing.T) { }, "test2": []*backend.CompactedBlockMeta{}, }, - expectedBlockMetaCalls: map[string]map[google_uuid.UUID]int{}, + expectedBlockMetaCalls: map[string]map[uuid.UUID]int{}, }, } @@ -943,12 +942,12 @@ func TestPollComparePreviousResults(t *testing.T) { for tenantID, expectedMetas := range tc.expectedPerTenant { l := metas[tenantID] sort.Slice(l, func(i, j int) bool { - x := bytes.Compare(l[i].BlockID.UUID[:], l[j].BlockID.UUID[:]) + x := bytes.Compare(l[i].BlockID[:], l[j].BlockID[:]) return x > 0 }) sort.Slice(expectedMetas, func(i, j int) bool { - x := bytes.Compare(expectedMetas[i].BlockID.UUID[:], expectedMetas[j].BlockID.UUID[:]) + x := bytes.Compare(expectedMetas[i].BlockID[:], expectedMetas[j].BlockID[:]) return x > 0 }) @@ -959,12 +958,12 @@ func TestPollComparePreviousResults(t *testing.T) { for tenantID, expectedCompactedMetas := range tc.expectedCompactedPerTenant { l := compactedMetas[tenantID] sort.Slice(l, func(i, j int) bool { - x := bytes.Compare(l[i].BlockID.UUID[:], l[j].BlockID.UUID[:]) + x := bytes.Compare(l[i].BlockID[:], l[j].BlockID[:]) return x > 0 }) sort.Slice(expectedCompactedMetas, func(i, j int) bool { - x := bytes.Compare(expectedCompactedMetas[i].BlockID.UUID[:], expectedCompactedMetas[j].BlockID.UUID[:]) + x := bytes.Compare(expectedCompactedMetas[i].BlockID[:], expectedCompactedMetas[j].BlockID[:]) return x > 0 }) require.Equal(t, expectedCompactedMetas, l) @@ -1045,7 +1044,7 @@ func newBlockMetas(count int) []*backend.BlockMeta { metas := make([]*backend.BlockMeta, count) for i := 0; i < count; i++ { metas[i] = &backend.BlockMeta{ - BlockID: uuid.New(), + BlockID: backend.NewUUID(), } } @@ -1057,7 +1056,7 @@ func newCompactedMetas(count int) []*backend.CompactedBlockMeta { for i := 0; i < count; i++ { metas[i] = &backend.CompactedBlockMeta{ BlockMeta: backend.BlockMeta{ - BlockID: uuid.New(), + BlockID: backend.NewUUID(), }, } } @@ -1103,7 +1102,7 @@ func newPerTenantCompacted(tenantCount, blockCount int) PerTenantCompacted { func newMockCompactor(list PerTenantCompacted, expectsError bool) backend.Compactor { return &backend.MockCompactor{ - BlockMetaFn: func(blockID google_uuid.UUID, tenantID string) (*backend.CompactedBlockMeta, error) { + BlockMetaFn: func(blockID uuid.UUID, tenantID string) (*backend.CompactedBlockMeta, error) { if expectsError { return nil, errors.New("err") } @@ -1114,7 +1113,7 @@ func newMockCompactor(list PerTenantCompacted, expectsError bool) backend.Compac } for _, m := range l { - if m.BlockID.UUID == blockID { + if (uuid.UUID)(m.BlockID) == blockID { return m, nil } } @@ -1141,25 +1140,25 @@ func newMockReader(list PerTenant, compactedList PerTenantCompacted, expectsErro return &backend.MockReader{ T: tenants, - BlocksFn: func(_ context.Context, tenantID string) ([]google_uuid.UUID, []google_uuid.UUID, error) { + BlocksFn: func(_ context.Context, tenantID string) ([]uuid.UUID, []uuid.UUID, error) { if expectsError { return nil, nil, errors.New("err") } blocks := list[tenantID] - uuids := []google_uuid.UUID{} - compactedUUIDs := []google_uuid.UUID{} + uuids := []uuid.UUID{} + compactedUUIDs := []uuid.UUID{} for _, b := range blocks { - uuids = append(uuids, b.BlockID.UUID) + uuids = append(uuids, (uuid.UUID)(b.BlockID)) } compactedBlocks := compactedList[tenantID] for _, b := range compactedBlocks { - compactedUUIDs = append(compactedUUIDs, b.BlockID.UUID) + compactedUUIDs = append(compactedUUIDs, (uuid.UUID)(b.BlockID)) } return uuids, compactedUUIDs, nil }, - BlockMetaCalls: make(map[string]map[google_uuid.UUID]int), - BlockMetaFn: func(_ context.Context, blockID google_uuid.UUID, tenantID string) (*backend.BlockMeta, error) { + BlockMetaCalls: make(map[string]map[uuid.UUID]int), + BlockMetaFn: func(_ context.Context, blockID uuid.UUID, tenantID string) (*backend.BlockMeta, error) { if expectsError { return nil, errors.New("err") } @@ -1170,7 +1169,7 @@ func newMockReader(list PerTenant, compactedList PerTenantCompacted, expectsErro } for _, m := range l { - if m.BlockID.UUID == blockID { + if (uuid.UUID)(m.BlockID) == blockID { return m, nil } } diff --git a/tempodb/compaction_block_selector_test.go b/tempodb/compaction_block_selector_test.go index ed14a8294cc..5614747b34b 100644 --- a/tempodb/compaction_block_selector_test.go +++ b/tempodb/compaction_block_selector_test.go @@ -5,7 +5,6 @@ import ( "testing" "time" - "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/stretchr/testify/assert" ) @@ -40,21 +39,21 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "only two", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, }, }, @@ -64,17 +63,17 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "choose smallest two", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), TotalObjects: 0, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000000"), TotalObjects: 1, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), TotalObjects: 0, EndTime: now, }, @@ -82,12 +81,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { maxInputBlocks: 2, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), TotalObjects: 0, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), TotalObjects: 0, EndTime: now, }, @@ -98,40 +97,40 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "different windows", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now.Add(-timeWindow), }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now.Add(-timeWindow), }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, }, }, expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 0), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now.Add(-timeWindow), }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now.Add(-timeWindow), }, }, @@ -141,22 +140,22 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "different sizes", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, TotalObjects: 15, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, TotalObjects: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now, TotalObjects: 3, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, TotalObjects: 12, }, @@ -164,12 +163,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { maxInputBlocks: 2, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, TotalObjects: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now, TotalObjects: 3, }, @@ -177,12 +176,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 0), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, TotalObjects: 12, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, TotalObjects: 15, }, @@ -193,43 +192,43 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "different compaction lvls", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, }, }, expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 0), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now, CompactionLevel: 1, }, @@ -240,48 +239,48 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "active time window vs not", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now.Add(-activeWindowDuration - time.Minute), CompactionLevel: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now.Add(-activeWindowDuration - time.Minute), CompactionLevel: 0, }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now, }, }, expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 0), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now.Add(-activeWindowDuration - time.Minute), CompactionLevel: 0, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now.Add(-activeWindowDuration - time.Minute), CompactionLevel: 1, }, @@ -292,50 +291,50 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "choose lowest compaction level", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now.Add(-timeWindow), }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000005"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000005"), EndTime: now.Add(-timeWindow), }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now, }, }, expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 0), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now.Add(-timeWindow), }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000005"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000005"), EndTime: now.Add(-timeWindow), }, }, @@ -345,11 +344,11 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "doesn't choose across time windows", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now.Add(-timeWindow), }, }, @@ -362,12 +361,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "doesn't exceed max compaction objects", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), TotalObjects: 99, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), TotalObjects: 2, EndTime: now, }, @@ -381,12 +380,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "doesn't exceed max block size", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), Size_: 50, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), Size_: 51, EndTime: now, }, @@ -401,29 +400,29 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "Returns as many blocks as possible without exceeding max compaction objects", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), TotalObjects: 50, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), TotalObjects: 50, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000003"), TotalObjects: 50, EndTime: now, }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), TotalObjects: 50, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), TotalObjects: 50, EndTime: now, }, @@ -437,29 +436,29 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { maxBlockBytes: 100, blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), Size_: 50, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), Size_: 50, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000003"), Size_: 1, EndTime: now, }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), Size_: 50, EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), Size_: 50, EndTime: now, }, @@ -474,44 +473,44 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { maxInputBlocks: 3, blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, TotalObjects: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, TotalObjects: 2, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now, TotalObjects: 3, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, TotalObjects: 4, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000005"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000005"), EndTime: now, TotalObjects: 5, }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, TotalObjects: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, TotalObjects: 2, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now, TotalObjects: 3, }, @@ -519,12 +518,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 0), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, TotalObjects: 4, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000005"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000005"), EndTime: now, TotalObjects: 5, }, @@ -535,11 +534,11 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "honors minimum block count", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, }, }, @@ -554,22 +553,22 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "can choose blocks not at the lowest compaction level", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, CompactionLevel: 0, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, CompactionLevel: 1, }, @@ -578,17 +577,17 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { maxInputBlocks: 3, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now, CompactionLevel: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, CompactionLevel: 1, }, @@ -601,12 +600,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "doesn't select blocks in last active window", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now.Add(-activeWindowDuration), CompactionLevel: 0, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now.Add(-activeWindowDuration), CompactionLevel: 0, }, @@ -616,12 +615,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "don't compact across dataEncodings", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000000"), EndTime: now, DataEncoding: "bar", }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, DataEncoding: "foo", }, @@ -632,12 +631,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "ensures blocks of different versions are not compacted", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, Version: "v2", }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, Version: "vParquet3", }, @@ -651,34 +650,34 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "ensures blocks of the same version are compacted", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, Version: "v2", }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, Version: "vParquet3", }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now, Version: "v2", }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, Version: "vParquet3", }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, Version: "v2", }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now, Version: "v2", }, @@ -686,12 +685,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 0), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, Version: "vParquet3", }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, Version: "vParquet3", }, @@ -702,28 +701,28 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "blocks with different dedicated columns are not selected together", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, DedicatedColumns: backend.DedicatedColumns{ {Scope: "span", Name: "foo", Type: "int"}, }, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, DedicatedColumns: backend.DedicatedColumns{ {Scope: "span", Name: "foo", Type: "string"}, }, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now, DedicatedColumns: backend.DedicatedColumns{ {Scope: "span", Name: "foo", Type: "int"}, }, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, DedicatedColumns: backend.DedicatedColumns{ {Scope: "span", Name: "foo", Type: "string"}, @@ -732,14 +731,14 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { }, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, DedicatedColumns: backend.DedicatedColumns{ {Scope: "span", Name: "foo", Type: "int"}, }, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now, DedicatedColumns: backend.DedicatedColumns{ {Scope: "span", Name: "foo", Type: "int"}, @@ -749,14 +748,14 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 0), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, DedicatedColumns: backend.DedicatedColumns{ {Scope: "span", Name: "foo", Type: "string"}, }, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, DedicatedColumns: backend.DedicatedColumns{ {Scope: "span", Name: "foo", Type: "string"}, @@ -769,34 +768,34 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { name: "blocks are grouped by replication factor", blocklist: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, ReplicationFactor: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, ReplicationFactor: 3, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now, ReplicationFactor: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, ReplicationFactor: 3, }, }, expected: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), EndTime: now, ReplicationFactor: 1, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000003"), EndTime: now, ReplicationFactor: 1, }, @@ -804,12 +803,12 @@ func TestTimeWindowBlockSelectorBlocksToCompact(t *testing.T) { expectedHash: fmt.Sprintf("%v-%v-%v-%v", tenantID, 0, now.Unix(), 1), expectedSecond: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), EndTime: now, ReplicationFactor: 3, }, { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000004"), EndTime: now, ReplicationFactor: 3, }, diff --git a/tempodb/compactor.go b/tempodb/compactor.go index 5fabd0cd845..2b4efb8abaa 100644 --- a/tempodb/compactor.go +++ b/tempodb/compactor.go @@ -9,6 +9,7 @@ import ( "time" "github.com/go-kit/log/level" + "github.com/google/uuid" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "go.opentelemetry.io/otel" @@ -201,7 +202,7 @@ func (rw *readerWriter) compact(ctx context.Context, blockMetas []*backend.Block totalRecords += int(blockMeta.TotalObjects) // Make sure block still exists - _, err = rw.r.BlockMeta(ctx, blockMeta.BlockID.UUID, tenantID) + _, err = rw.r.BlockMeta(ctx, (uuid.UUID)(blockMeta.BlockID), tenantID) if err != nil { return err } @@ -283,7 +284,7 @@ func markCompacted(rw *readerWriter, tenantID string, oldBlocks, newBlocks []*ba var errCount int for _, meta := range oldBlocks { // Mark in the backend - if err := rw.c.MarkBlockCompacted(meta.BlockID.UUID, tenantID); err != nil { + if err := rw.c.MarkBlockCompacted((uuid.UUID)(meta.BlockID), tenantID); err != nil { errCount++ level.Error(rw.logger).Log("msg", "unable to mark block compacted", "blockID", meta.BlockID, "tenantID", tenantID, "err", err) metricCompactionErrors.Inc() diff --git a/tempodb/compactor_test.go b/tempodb/compactor_test.go index 1b1bf543503..9c57c00c62e 100644 --- a/tempodb/compactor_test.go +++ b/tempodb/compactor_test.go @@ -12,7 +12,7 @@ import ( "github.com/go-kit/log" proto "github.com/gogo/protobuf/proto" - google_uuid "github.com/google/uuid" + "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -21,7 +21,6 @@ import ( v1 "github.com/grafana/tempo/pkg/model/v1" "github.com/grafana/tempo/pkg/tempopb" "github.com/grafana/tempo/pkg/util/test" - "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/backend/local" "github.com/grafana/tempo/tempodb/blocklist" @@ -132,7 +131,7 @@ func testCompactionRoundtrip(t *testing.T, targetBlockVersion string) { allIds := make([]common.ID, 0, blockCount*recordCount) for i := 0; i < blockCount; i++ { - blockID := uuid.New() + blockID := backend.NewUUID() meta := &backend.BlockMeta{BlockID: blockID, TenantID: testTenantID, DataEncoding: model.CurrentEncoding} head, err := wal.NewBlock(meta, model.CurrentEncoding) require.NoError(t, err) @@ -155,7 +154,7 @@ func testCompactionRoundtrip(t *testing.T, targetBlockVersion string) { expectedBlockCount := blockCount expectedCompactedCount := 0 - checkBlocklists(t, google_uuid.Nil, expectedBlockCount, expectedCompactedCount, rw) + checkBlocklists(t, uuid.Nil, expectedBlockCount, expectedCompactedCount, rw) blocksPerCompaction := (inputBlocks - outputBlocks) @@ -179,7 +178,7 @@ func testCompactionRoundtrip(t *testing.T, targetBlockVersion string) { expectedBlockCount -= blocksPerCompaction expectedCompactedCount += inputBlocks - checkBlocklists(t, google_uuid.Nil, expectedBlockCount, expectedCompactedCount, rw) + checkBlocklists(t, uuid.Nil, expectedBlockCount, expectedCompactedCount, rw) } require.Equal(t, expectedCompactions, compactions) @@ -304,7 +303,7 @@ func testSameIDCompaction(t *testing.T, targetBlockVersion string) { // and write them to different blocks for i := 0; i < blockCount; i++ { - blockID := uuid.New() + blockID := backend.NewUUID() meta := &backend.BlockMeta{BlockID: blockID, TenantID: testTenantID, DataEncoding: v1.Encoding} head, err := wal.NewBlock(meta, v1.Encoding) require.NoError(t, err) @@ -326,7 +325,7 @@ func testSameIDCompaction(t *testing.T, targetBlockVersion string) { rw := r.(*readerWriter) // check blocklists, force compaction and check again - checkBlocklists(t, google_uuid.Nil, blockCount, 0, rw) + checkBlocklists(t, uuid.Nil, blockCount, 0, rw) var blocks []*backend.BlockMeta list := rw.blocklist.Metas(testTenantID) @@ -340,7 +339,7 @@ func testSameIDCompaction(t *testing.T, targetBlockVersion string) { err = rw.compact(ctx, blocks, testTenantID) require.NoError(t, err) - checkBlocklists(t, google_uuid.Nil, 1, blockCount, rw) + checkBlocklists(t, uuid.Nil, 1, blockCount, rw) // force clear compacted blocks to guarantee that we're only querying the new blocks that went through the combiner metas := rw.blocklist.Metas(testTenantID) @@ -703,7 +702,7 @@ func testCompactionDropsTraces(t *testing.T, targetBlockVersion string) { allIDs := make([]common.ID, 0, recordCount) // write a bunch of dummy data - blockID := uuid.New() + blockID := backend.NewUUID() meta := &backend.BlockMeta{BlockID: blockID, TenantID: testTenantID, DataEncoding: v1.Encoding} head, err := wal.NewBlock(meta, v1.Encoding) require.NoError(t, err) @@ -790,7 +789,7 @@ func cutTestBlockWithTraces(t testing.TB, w Writer, tenantID string, data []test wal := w.WAL() - meta := &backend.BlockMeta{BlockID: uuid.New(), TenantID: testTenantID} + meta := &backend.BlockMeta{BlockID: backend.NewUUID(), TenantID: testTenantID} head, err := wal.NewBlock(meta, model.CurrentEncoding) require.NoError(t, err) @@ -810,7 +809,7 @@ func cutTestBlocks(t testing.TB, w Writer, tenantID string, blockCount int, reco wal := w.WAL() for i := 0; i < blockCount; i++ { - meta := &backend.BlockMeta{BlockID: uuid.New(), TenantID: tenantID} + meta := &backend.BlockMeta{BlockID: backend.NewUUID(), TenantID: tenantID} head, err := wal.NewBlock(meta, model.CurrentEncoding) require.NoError(t, err) diff --git a/tempodb/encoding/v2/backend_block.go b/tempodb/encoding/v2/backend_block.go index 50c230b581a..13995133cc4 100644 --- a/tempodb/encoding/v2/backend_block.go +++ b/tempodb/encoding/v2/backend_block.go @@ -5,6 +5,7 @@ import ( "context" "fmt" + "github.com/google/uuid" willf_bloom "github.com/willf/bloom" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" @@ -55,7 +56,7 @@ func (b *BackendBlock) find(ctx context.Context, id common.ID) ([]byte, error) { tenantID := b.meta.TenantID nameBloom := common.BloomName(shardKey) - bloomBytes, err := b.reader.Read(ctx, nameBloom, blockID.UUID, tenantID, &backend.CacheInfo{ + bloomBytes, err := b.reader.Read(ctx, nameBloom, (uuid.UUID)(blockID), tenantID, &backend.CacheInfo{ Meta: b.meta, Role: cache.RoleBloom, }) diff --git a/tempodb/encoding/v2/backend_block_test.go b/tempodb/encoding/v2/backend_block_test.go index efb19d3e348..bb7337fba62 100644 --- a/tempodb/encoding/v2/backend_block_test.go +++ b/tempodb/encoding/v2/backend_block_test.go @@ -52,7 +52,7 @@ func testLegacyBlock(t *testing.T, ids [][]byte, objs [][]byte, meta *backend.Bl require.NoError(t, err, "error creating backend") reader := backend.NewReader(r) - meta, err = reader.BlockMeta(context.Background(), meta.BlockID.UUID, meta.TenantID) + meta, err = reader.BlockMeta(context.Background(), (uuid.UUID)(meta.BlockID), meta.TenantID) require.NoError(t, err, "error retrieving meta") backendBlock, err := NewBackendBlock(meta, reader) diff --git a/tempodb/encoding/v2/block.go b/tempodb/encoding/v2/block.go index 8a7cf3bdd6c..112a06b6d76 100644 --- a/tempodb/encoding/v2/block.go +++ b/tempodb/encoding/v2/block.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/google/uuid" "github.com/grafana/tempo/pkg/cache" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/encoding/common" @@ -17,7 +18,7 @@ func writeBlockMeta(ctx context.Context, w backend.Writer, meta *backend.BlockMe } // index - err = w.Write(ctx, common.NameIndex, meta.BlockID.UUID, meta.TenantID, indexBytes, nil) + err = w.Write(ctx, common.NameIndex, (uuid.UUID)(meta.BlockID), meta.TenantID, indexBytes, nil) if err != nil { return fmt.Errorf("unexpected error writing index: %w", err) } @@ -29,7 +30,7 @@ func writeBlockMeta(ctx context.Context, w backend.Writer, meta *backend.BlockMe // bloom for i, bloom := range blooms { nameBloom := common.BloomName(i) - err := w.Write(ctx, nameBloom, meta.BlockID.UUID, meta.TenantID, bloom, cacheInfo) + err := w.Write(ctx, nameBloom, (uuid.UUID)(meta.BlockID), meta.TenantID, bloom, cacheInfo) if err != nil { return fmt.Errorf("unexpected error writing bloom-%d: %w", i, err) } @@ -46,20 +47,20 @@ func writeBlockMeta(ctx context.Context, w backend.Writer, meta *backend.BlockMe // appendBlockData appends the bytes passed to the block data func appendBlockData(ctx context.Context, w backend.Writer, meta *backend.BlockMeta, tracker backend.AppendTracker, buffer []byte) (backend.AppendTracker, error) { - return w.Append(ctx, common.NameObjects, meta.BlockID.UUID, meta.TenantID, tracker, buffer) + return w.Append(ctx, common.NameObjects, (uuid.UUID)(meta.BlockID), meta.TenantID, tracker, buffer) } // CopyBlock copies a block from one backend to another. It is done at a low level, all encoding/formatting is preserved. func CopyBlock(ctx context.Context, srcMeta, destMeta *backend.BlockMeta, src backend.Reader, dest backend.Writer) error { // Copy streams, efficient but can't cache. copyStream := func(name string) error { - reader, size, err := src.StreamReader(ctx, name, srcMeta.BlockID.UUID, srcMeta.TenantID) + reader, size, err := src.StreamReader(ctx, name, (uuid.UUID)(srcMeta.BlockID), srcMeta.TenantID) if err != nil { return fmt.Errorf("error reading %s: %w", name, err) } defer reader.Close() - return dest.StreamWriter(ctx, name, destMeta.BlockID.UUID, destMeta.TenantID, reader, size) + return dest.StreamWriter(ctx, name, (uuid.UUID)(destMeta.BlockID), destMeta.TenantID, reader, size) } cacheInfo := &backend.CacheInfo{ @@ -69,13 +70,13 @@ func CopyBlock(ctx context.Context, srcMeta, destMeta *backend.BlockMeta, src ba // Read entire object and attempt to cache cpyBloom := func(name string) error { cacheInfo.Meta = srcMeta - b, err := src.Read(ctx, name, srcMeta.BlockID.UUID, srcMeta.TenantID, cacheInfo) + b, err := src.Read(ctx, name, (uuid.UUID)(srcMeta.BlockID), srcMeta.TenantID, cacheInfo) if err != nil { return fmt.Errorf("error reading %s: %w", name, err) } cacheInfo.Meta = destMeta - return dest.Write(ctx, name, destMeta.BlockID.UUID, destMeta.TenantID, b, cacheInfo) + return dest.Write(ctx, name, (uuid.UUID)(destMeta.BlockID), destMeta.TenantID, b, cacheInfo) } // Data diff --git a/tempodb/encoding/v2/create_block.go b/tempodb/encoding/v2/create_block.go index 240628009d8..3de5d80cca0 100644 --- a/tempodb/encoding/v2/create_block.go +++ b/tempodb/encoding/v2/create_block.go @@ -6,6 +6,7 @@ import ( "fmt" "io" + "github.com/google/uuid" "github.com/grafana/tempo/pkg/model" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/encoding/common" @@ -19,7 +20,7 @@ func CreateBlock(ctx context.Context, cfg *common.BlockConfig, meta *backend.Blo meta.DataEncoding = model.CurrentEncoding } - newBlock, err := NewStreamingBlock(cfg, meta.BlockID.UUID, meta.TenantID, []*backend.BlockMeta{meta}, int(meta.TotalObjects)) + newBlock, err := NewStreamingBlock(cfg, (uuid.UUID)(meta.BlockID), meta.TenantID, []*backend.BlockMeta{meta}, int(meta.TotalObjects)) if err != nil { return nil, fmt.Errorf("error creating streaming block: %w", err) } diff --git a/tempodb/encoding/v2/streaming_block_test.go b/tempodb/encoding/v2/streaming_block_test.go index 71f0d0b25d0..59db0b7cb8a 100644 --- a/tempodb/encoding/v2/streaming_block_test.go +++ b/tempodb/encoding/v2/streaming_block_test.go @@ -253,7 +253,7 @@ func streamingBlock(t *testing.T, cfg *common.BlockConfig, w backend.Writer) (*S dataReader, NewObjectReaderWriter()) - block, err := NewStreamingBlock(cfg, originatingMeta.BlockID.UUID, originatingMeta.TenantID, []*backend.BlockMeta{originatingMeta}, int(originatingMeta.TotalObjects)) + block, err := NewStreamingBlock(cfg, (uuid.UUID)(originatingMeta.BlockID), originatingMeta.TenantID, []*backend.BlockMeta{originatingMeta}, int(originatingMeta.TotalObjects)) require.NoError(t, err, "unexpected error completing block") expectedBloomShards := block.bloom.GetShardCount() diff --git a/tempodb/encoding/v2/wal_block.go b/tempodb/encoding/v2/wal_block.go index 13b05c7e149..f28818546de 100644 --- a/tempodb/encoding/v2/wal_block.go +++ b/tempodb/encoding/v2/wal_block.go @@ -54,7 +54,7 @@ func createWALBlock(meta *backend.BlockMeta, filepath, dataEncoding string, inge } h := &walBlock{ - meta: backend.NewBlockMeta(meta.TenantID, meta.BlockID.UUID, meta.Version, meta.Encoding, dataEncoding), + meta: backend.NewBlockMeta(meta.TenantID, (uuid.UUID)(meta.BlockID), meta.Version, meta.Encoding, dataEncoding), filepath: filepath, ingestionSlack: ingestionSlack, encoder: enc, diff --git a/tempodb/encoding/vparquet2/block_findtracebyid.go b/tempodb/encoding/vparquet2/block_findtracebyid.go index c11b7f8950f..5ec1515c74e 100644 --- a/tempodb/encoding/vparquet2/block_findtracebyid.go +++ b/tempodb/encoding/vparquet2/block_findtracebyid.go @@ -8,6 +8,7 @@ import ( "io" "os" + "github.com/google/uuid" "github.com/parquet-go/parquet-go" "github.com/willf/bloom" "go.opentelemetry.io/otel/attribute" @@ -45,7 +46,7 @@ func (b *backendBlock) checkBloom(ctx context.Context, id common.ID) (found bool nameBloom := common.BloomName(shardKey) span.SetAttributes(attribute.String("bloom", nameBloom)) - bloomBytes, err := b.r.Read(derivedCtx, nameBloom, b.meta.BlockID.UUID, b.meta.TenantID, &backend.CacheInfo{ + bloomBytes, err := b.r.Read(derivedCtx, nameBloom, (uuid.UUID)(b.meta.BlockID), b.meta.TenantID, &backend.CacheInfo{ Meta: b.meta, Role: cache.RoleBloom, }) @@ -75,7 +76,7 @@ func (b *backendBlock) checkIndex(ctx context.Context, id common.ID) (bool, int, )) defer span.End() - indexBytes, err := b.r.Read(derivedCtx, common.NameIndex, b.meta.BlockID.UUID, b.meta.TenantID, &backend.CacheInfo{ + indexBytes, err := b.r.Read(derivedCtx, common.NameIndex, (uuid.UUID)(b.meta.BlockID), b.meta.TenantID, &backend.CacheInfo{ Meta: b.meta, Role: cache.RoleTraceIDIdx, }) diff --git a/tempodb/encoding/vparquet2/compactor.go b/tempodb/encoding/vparquet2/compactor.go index 94462e43846..ce4da0eda34 100644 --- a/tempodb/encoding/vparquet2/compactor.go +++ b/tempodb/encoding/vparquet2/compactor.go @@ -15,7 +15,6 @@ import ( "github.com/parquet-go/parquet-go" tempo_io "github.com/grafana/tempo/pkg/io" - "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/encoding/common" ) @@ -150,7 +149,7 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, if currentBlock == nil { // Start with a copy and then customize newMeta := &backend.BlockMeta{ - BlockID: uuid.New(), + BlockID: backend.NewUUID(), TenantID: inputs[0].TenantID, CompactionLevel: nextCompactionLevel, TotalObjects: recordsPerBlock, // Just an estimate diff --git a/tempodb/encoding/vparquet2/compactor_test.go b/tempodb/encoding/vparquet2/compactor_test.go index 85c9da43c3e..02f236d2756 100644 --- a/tempodb/encoding/vparquet2/compactor_test.go +++ b/tempodb/encoding/vparquet2/compactor_test.go @@ -13,7 +13,6 @@ import ( tempo_io "github.com/grafana/tempo/pkg/io" "github.com/grafana/tempo/pkg/util/test" - "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/backend/local" "github.com/grafana/tempo/tempodb/encoding/common" @@ -113,7 +112,7 @@ func BenchmarkCompactorDupes(b *testing.B) { func createTestBlock(t testing.TB, ctx context.Context, cfg *common.BlockConfig, r backend.Reader, w backend.Writer, traceCount, batchCount, spanCount int) *backend.BlockMeta { inMeta := &backend.BlockMeta{ TenantID: tenantID, - BlockID: uuid.New(), + BlockID: backend.NewUUID(), TotalObjects: int32(traceCount), } diff --git a/tempodb/encoding/vparquet2/copy.go b/tempodb/encoding/vparquet2/copy.go index 01342d73fb9..6169ee69be0 100644 --- a/tempodb/encoding/vparquet2/copy.go +++ b/tempodb/encoding/vparquet2/copy.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" + "github.com/google/uuid" "github.com/grafana/tempo/pkg/cache" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/encoding/common" @@ -13,25 +14,25 @@ import ( func CopyBlock(ctx context.Context, fromMeta, toMeta *backend.BlockMeta, from backend.Reader, to backend.Writer) error { // Copy streams, efficient but can't cache. copyStream := func(name string) error { - reader, size, err := from.StreamReader(ctx, name, fromMeta.BlockID.UUID, fromMeta.TenantID) + reader, size, err := from.StreamReader(ctx, name, (uuid.UUID)(fromMeta.BlockID), fromMeta.TenantID) if err != nil { return fmt.Errorf("error reading %s: %w", name, err) } defer reader.Close() - return to.StreamWriter(ctx, name, toMeta.BlockID.UUID, toMeta.TenantID, reader, size) + return to.StreamWriter(ctx, name, (uuid.UUID)(toMeta.BlockID), toMeta.TenantID, reader, size) } // Read entire object and attempt to cache cpy := func(name string, cacheInfo *backend.CacheInfo) error { cacheInfo.Meta = fromMeta - b, err := from.Read(ctx, name, fromMeta.BlockID.UUID, fromMeta.TenantID, cacheInfo) + b, err := from.Read(ctx, name, (uuid.UUID)(fromMeta.BlockID), fromMeta.TenantID, cacheInfo) if err != nil { return fmt.Errorf("error reading %s: %w", name, err) } cacheInfo.Meta = toMeta - return to.Write(ctx, name, toMeta.BlockID.UUID, toMeta.TenantID, b, cacheInfo) + return to.Write(ctx, name, (uuid.UUID)(toMeta.BlockID), toMeta.TenantID, b, cacheInfo) } // Data @@ -72,7 +73,7 @@ func writeBlockMeta(ctx context.Context, w backend.Writer, meta *backend.BlockMe } for i, bloom := range blooms { nameBloom := common.BloomName(i) - err := w.Write(ctx, nameBloom, meta.BlockID.UUID, meta.TenantID, bloom, cacheInfo) + err := w.Write(ctx, nameBloom, (uuid.UUID)(meta.BlockID), meta.TenantID, bloom, cacheInfo) if err != nil { return fmt.Errorf("unexpected error writing bloom-%d: %w", i, err) } @@ -83,7 +84,7 @@ func writeBlockMeta(ctx context.Context, w backend.Writer, meta *backend.BlockMe if err != nil { return err } - err = w.Write(ctx, common.NameIndex, meta.BlockID.UUID, meta.TenantID, i, &backend.CacheInfo{ + err = w.Write(ctx, common.NameIndex, (uuid.UUID)(meta.BlockID), meta.TenantID, i, &backend.CacheInfo{ Meta: meta, Role: cache.RoleTraceIDIdx, }) diff --git a/tempodb/encoding/vparquet2/create.go b/tempodb/encoding/vparquet2/create.go index c6002594ee2..a7a2e0920eb 100644 --- a/tempodb/encoding/vparquet2/create.go +++ b/tempodb/encoding/vparquet2/create.go @@ -107,7 +107,7 @@ type streamingBlock struct { } func newStreamingBlock(ctx context.Context, cfg *common.BlockConfig, meta *backend.BlockMeta, r backend.Reader, to backend.Writer, createBufferedWriter func(w io.Writer) tempo_io.BufferedWriteFlusher) *streamingBlock { - newMeta := backend.NewBlockMeta(meta.TenantID, meta.BlockID.UUID, VersionString, backend.EncNone, "") + newMeta := backend.NewBlockMeta(meta.TenantID, (uuid.UUID)(meta.BlockID), VersionString, backend.EncNone, "") newMeta.StartTime = meta.StartTime newMeta.EndTime = meta.EndTime @@ -115,7 +115,7 @@ func newStreamingBlock(ctx context.Context, cfg *common.BlockConfig, meta *backe // The real number of objects is tracked below. bloom := common.NewBloom(cfg.BloomFP, uint(cfg.BloomShardSizeBytes), uint(meta.TotalObjects)) - w := &backendWriter{ctx, to, DataFileName, meta.BlockID.UUID, meta.TenantID, nil} + w := &backendWriter{ctx, to, DataFileName, (uuid.UUID)(meta.BlockID), meta.TenantID, nil} bw := createBufferedWriter(w) pw := parquet.NewGenericWriter[*Trace](bw) @@ -224,7 +224,7 @@ func (b *streamingBlock) Complete() (int, error) { // Read the footer size out of the parquet footer buf := make([]byte, 8) - err = b.r.ReadRange(b.ctx, DataFileName, b.meta.BlockID.UUID, b.meta.TenantID, b.meta.Size_-8, buf, nil) + err = b.r.ReadRange(b.ctx, DataFileName, (uuid.UUID)(b.meta.BlockID), b.meta.TenantID, b.meta.Size_-8, buf, nil) if err != nil { return 0, fmt.Errorf("error reading parquet file footer: %w", err) } diff --git a/tempodb/encoding/vparquet2/readers.go b/tempodb/encoding/vparquet2/readers.go index 6afba79a672..ec804f712b2 100644 --- a/tempodb/encoding/vparquet2/readers.go +++ b/tempodb/encoding/vparquet2/readers.go @@ -7,6 +7,7 @@ import ( "go.uber.org/atomic" + "github.com/google/uuid" "github.com/grafana/tempo/pkg/cache" "github.com/grafana/tempo/tempodb/backend" ) @@ -36,7 +37,7 @@ func NewBackendReaderAt(ctx context.Context, r backend.Reader, name string, meta func (b *BackendReaderAt) ReadAt(p []byte, off int64) (int, error) { b.bytesRead.Add(uint64(len(p))) - err := b.r.ReadRange(b.ctx, b.name, b.meta.BlockID.UUID, b.meta.TenantID, uint64(off), p, nil) + err := b.r.ReadRange(b.ctx, b.name, (uuid.UUID)(b.meta.BlockID), b.meta.TenantID, uint64(off), p, nil) if err != nil { return 0, err } @@ -44,7 +45,7 @@ func (b *BackendReaderAt) ReadAt(p []byte, off int64) (int, error) { } func (b *BackendReaderAt) ReadAtWithCache(p []byte, off int64, role cache.Role) (int, error) { - err := b.r.ReadRange(b.ctx, b.name, b.meta.BlockID.UUID, b.meta.TenantID, uint64(off), p, &backend.CacheInfo{ + err := b.r.ReadRange(b.ctx, b.name, (uuid.UUID)(b.meta.BlockID), b.meta.TenantID, uint64(off), p, &backend.CacheInfo{ Role: role, Meta: b.meta, }) diff --git a/tempodb/encoding/vparquet3/block_findtracebyid.go b/tempodb/encoding/vparquet3/block_findtracebyid.go index 84aaf497b10..90055c436de 100644 --- a/tempodb/encoding/vparquet3/block_findtracebyid.go +++ b/tempodb/encoding/vparquet3/block_findtracebyid.go @@ -8,6 +8,7 @@ import ( "io" "os" + "github.com/google/uuid" "github.com/parquet-go/parquet-go" "github.com/willf/bloom" "go.opentelemetry.io/otel/attribute" @@ -45,7 +46,7 @@ func (b *backendBlock) checkBloom(ctx context.Context, id common.ID) (found bool nameBloom := common.BloomName(shardKey) span.SetAttributes(attribute.String("bloom", nameBloom)) - bloomBytes, err := b.r.Read(derivedCtx, nameBloom, b.meta.BlockID.UUID, b.meta.TenantID, &backend.CacheInfo{ + bloomBytes, err := b.r.Read(derivedCtx, nameBloom, (uuid.UUID)(b.meta.BlockID), b.meta.TenantID, &backend.CacheInfo{ Meta: b.meta, Role: cache.RoleBloom, }) @@ -75,7 +76,7 @@ func (b *backendBlock) checkIndex(ctx context.Context, id common.ID) (bool, int, )) defer span.End() - indexBytes, err := b.r.Read(derivedCtx, common.NameIndex, b.meta.BlockID.UUID, b.meta.TenantID, &backend.CacheInfo{ + indexBytes, err := b.r.Read(derivedCtx, common.NameIndex, (uuid.UUID)(b.meta.BlockID), b.meta.TenantID, &backend.CacheInfo{ Meta: b.meta, Role: cache.RoleTraceIDIdx, }) diff --git a/tempodb/encoding/vparquet3/compactor.go b/tempodb/encoding/vparquet3/compactor.go index f169f62434c..971d491bb19 100644 --- a/tempodb/encoding/vparquet3/compactor.go +++ b/tempodb/encoding/vparquet3/compactor.go @@ -15,7 +15,6 @@ import ( "github.com/parquet-go/parquet-go" tempo_io "github.com/grafana/tempo/pkg/io" - "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/encoding/common" ) @@ -156,7 +155,7 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, if currentBlock == nil { // Start with a copy and then customize newMeta := &backend.BlockMeta{ - BlockID: uuid.New(), + BlockID: backend.NewUUID(), TenantID: inputs[0].TenantID, CompactionLevel: nextCompactionLevel, TotalObjects: recordsPerBlock, // Just an estimate diff --git a/tempodb/encoding/vparquet3/compactor_test.go b/tempodb/encoding/vparquet3/compactor_test.go index d4141495cc8..f5d8995c8b5 100644 --- a/tempodb/encoding/vparquet3/compactor_test.go +++ b/tempodb/encoding/vparquet3/compactor_test.go @@ -14,7 +14,6 @@ import ( tempo_io "github.com/grafana/tempo/pkg/io" tempoUtil "github.com/grafana/tempo/pkg/util" "github.com/grafana/tempo/pkg/util/test" - "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/backend/local" "github.com/grafana/tempo/tempodb/encoding/common" @@ -113,7 +112,7 @@ func BenchmarkCompactorDupes(b *testing.B) { func createTestBlock(t testing.TB, ctx context.Context, cfg *common.BlockConfig, r backend.Reader, w backend.Writer, traceCount, batchCount, spanCount, replicationFactor int, dc backend.DedicatedColumns) *backend.BlockMeta { inMeta := &backend.BlockMeta{ TenantID: tenantID, - BlockID: uuid.New(), + BlockID: backend.NewUUID(), TotalObjects: int32(traceCount), ReplicationFactor: uint32(replicationFactor), DedicatedColumns: dc, diff --git a/tempodb/encoding/vparquet3/copy.go b/tempodb/encoding/vparquet3/copy.go index eb5762e1d22..07430b074e2 100644 --- a/tempodb/encoding/vparquet3/copy.go +++ b/tempodb/encoding/vparquet3/copy.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" + "github.com/google/uuid" "github.com/grafana/tempo/pkg/cache" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/encoding/common" @@ -13,25 +14,25 @@ import ( func CopyBlock(ctx context.Context, fromMeta, toMeta *backend.BlockMeta, from backend.Reader, to backend.Writer) error { // Copy streams, efficient but can't cache. copyStream := func(name string) error { - reader, size, err := from.StreamReader(ctx, name, fromMeta.BlockID.UUID, fromMeta.TenantID) + reader, size, err := from.StreamReader(ctx, name, (uuid.UUID)(fromMeta.BlockID), fromMeta.TenantID) if err != nil { return fmt.Errorf("error reading %s: %w", name, err) } defer reader.Close() - return to.StreamWriter(ctx, name, toMeta.BlockID.UUID, toMeta.TenantID, reader, size) + return to.StreamWriter(ctx, name, (uuid.UUID)(toMeta.BlockID), toMeta.TenantID, reader, size) } // Read entire object and attempt to cache cpy := func(name string, cacheInfo *backend.CacheInfo) error { cacheInfo.Meta = fromMeta - b, err := from.Read(ctx, name, fromMeta.BlockID.UUID, fromMeta.TenantID, cacheInfo) + b, err := from.Read(ctx, name, (uuid.UUID)(fromMeta.BlockID), fromMeta.TenantID, cacheInfo) if err != nil { return fmt.Errorf("error reading %s: %w", name, err) } cacheInfo.Meta = toMeta - return to.Write(ctx, name, toMeta.BlockID.UUID, toMeta.TenantID, b, cacheInfo) + return to.Write(ctx, name, (uuid.UUID)(toMeta.BlockID), toMeta.TenantID, b, cacheInfo) } // Data @@ -73,7 +74,7 @@ func writeBlockMeta(ctx context.Context, w backend.Writer, meta *backend.BlockMe } for i, bloom := range blooms { nameBloom := common.BloomName(i) - err := w.Write(ctx, nameBloom, meta.BlockID.UUID, meta.TenantID, bloom, cacheInfo) + err := w.Write(ctx, nameBloom, (uuid.UUID)(meta.BlockID), meta.TenantID, bloom, cacheInfo) if err != nil { return fmt.Errorf("unexpected error writing bloom-%d: %w", i, err) } @@ -84,7 +85,7 @@ func writeBlockMeta(ctx context.Context, w backend.Writer, meta *backend.BlockMe if err != nil { return err } - err = w.Write(ctx, common.NameIndex, meta.BlockID.UUID, meta.TenantID, i, &backend.CacheInfo{ + err = w.Write(ctx, common.NameIndex, (uuid.UUID)(meta.BlockID), meta.TenantID, i, &backend.CacheInfo{ Meta: meta, Role: cache.RoleTraceIDIdx, }) diff --git a/tempodb/encoding/vparquet3/create.go b/tempodb/encoding/vparquet3/create.go index 03195e85511..fc6e7749611 100644 --- a/tempodb/encoding/vparquet3/create.go +++ b/tempodb/encoding/vparquet3/create.go @@ -107,7 +107,7 @@ type streamingBlock struct { } func newStreamingBlock(ctx context.Context, cfg *common.BlockConfig, meta *backend.BlockMeta, r backend.Reader, to backend.Writer, createBufferedWriter func(w io.Writer) tempo_io.BufferedWriteFlusher) *streamingBlock { - newMeta := backend.NewBlockMetaWithDedicatedColumns(meta.TenantID, meta.BlockID.UUID, VersionString, backend.EncNone, "", meta.DedicatedColumns) + newMeta := backend.NewBlockMetaWithDedicatedColumns(meta.TenantID, (uuid.UUID)(meta.BlockID), VersionString, backend.EncNone, "", meta.DedicatedColumns) newMeta.StartTime = meta.StartTime newMeta.EndTime = meta.EndTime newMeta.ReplicationFactor = meta.ReplicationFactor @@ -116,7 +116,7 @@ func newStreamingBlock(ctx context.Context, cfg *common.BlockConfig, meta *backe // The real number of objects is tracked below. bloom := common.NewBloom(cfg.BloomFP, uint(cfg.BloomShardSizeBytes), uint(meta.TotalObjects)) - w := &backendWriter{ctx, to, DataFileName, meta.BlockID.UUID, meta.TenantID, nil} + w := &backendWriter{ctx, to, DataFileName, (uuid.UUID)(meta.BlockID), meta.TenantID, nil} bw := createBufferedWriter(w) pw := parquet.NewGenericWriter[*Trace](bw) @@ -225,7 +225,7 @@ func (b *streamingBlock) Complete() (int, error) { // Read the footer size out of the parquet footer buf := make([]byte, 8) - err = b.r.ReadRange(b.ctx, DataFileName, b.meta.BlockID.UUID, b.meta.TenantID, b.meta.Size_-8, buf, nil) + err = b.r.ReadRange(b.ctx, DataFileName, (uuid.UUID)(b.meta.BlockID), b.meta.TenantID, b.meta.Size_-8, buf, nil) if err != nil { return 0, fmt.Errorf("error reading parquet file footer: %w", err) } diff --git a/tempodb/encoding/vparquet3/readers.go b/tempodb/encoding/vparquet3/readers.go index 1b8cc8f23e7..a86bbd91962 100644 --- a/tempodb/encoding/vparquet3/readers.go +++ b/tempodb/encoding/vparquet3/readers.go @@ -7,6 +7,7 @@ import ( "go.uber.org/atomic" + "github.com/google/uuid" "github.com/grafana/tempo/pkg/cache" "github.com/grafana/tempo/tempodb/backend" ) @@ -37,7 +38,7 @@ func (b *BackendReaderAt) ReadAt(p []byte, off int64) (int, error) { } func (b *BackendReaderAt) ReadAtWithCache(p []byte, off int64, role cache.Role) (int, error) { - err := b.r.ReadRange(b.ctx, b.name, b.meta.BlockID.UUID, b.meta.TenantID, uint64(off), p, &backend.CacheInfo{ + err := b.r.ReadRange(b.ctx, b.name, (uuid.UUID)(b.meta.BlockID), b.meta.TenantID, uint64(off), p, &backend.CacheInfo{ Role: role, Meta: b.meta, }) diff --git a/tempodb/encoding/vparquet4/block_findtracebyid.go b/tempodb/encoding/vparquet4/block_findtracebyid.go index c782bbf8c0e..d9f746c0151 100644 --- a/tempodb/encoding/vparquet4/block_findtracebyid.go +++ b/tempodb/encoding/vparquet4/block_findtracebyid.go @@ -8,6 +8,7 @@ import ( "io" "os" + "github.com/google/uuid" "github.com/parquet-go/parquet-go" "github.com/willf/bloom" "go.opentelemetry.io/otel/attribute" @@ -45,7 +46,7 @@ func (b *backendBlock) checkBloom(ctx context.Context, id common.ID) (found bool nameBloom := common.BloomName(shardKey) span.SetAttributes(attribute.String("bloom", nameBloom)) - bloomBytes, err := b.r.Read(derivedCtx, nameBloom, b.meta.BlockID.UUID, b.meta.TenantID, &backend.CacheInfo{ + bloomBytes, err := b.r.Read(derivedCtx, nameBloom, (uuid.UUID)(b.meta.BlockID), b.meta.TenantID, &backend.CacheInfo{ Meta: b.meta, Role: cache.RoleBloom, }) @@ -75,7 +76,7 @@ func (b *backendBlock) checkIndex(ctx context.Context, id common.ID) (bool, int, )) defer span.End() - indexBytes, err := b.r.Read(derivedCtx, common.NameIndex, b.meta.BlockID.UUID, b.meta.TenantID, &backend.CacheInfo{ + indexBytes, err := b.r.Read(derivedCtx, common.NameIndex, (uuid.UUID)(b.meta.BlockID), b.meta.TenantID, &backend.CacheInfo{ Meta: b.meta, Role: cache.RoleTraceIDIdx, }) diff --git a/tempodb/encoding/vparquet4/compactor.go b/tempodb/encoding/vparquet4/compactor.go index 10f342311a9..3e72f20ea88 100644 --- a/tempodb/encoding/vparquet4/compactor.go +++ b/tempodb/encoding/vparquet4/compactor.go @@ -16,7 +16,6 @@ import ( "go.opentelemetry.io/otel/attribute" tempo_io "github.com/grafana/tempo/pkg/io" - "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/encoding/common" ) @@ -157,7 +156,7 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, if currentBlock == nil { // Start with a copy and then customize newMeta := &backend.BlockMeta{ - BlockID: uuid.New(), + BlockID: backend.NewUUID(), TenantID: inputs[0].TenantID, CompactionLevel: nextCompactionLevel, TotalObjects: recordsPerBlock, // Just an estimate diff --git a/tempodb/encoding/vparquet4/compactor_test.go b/tempodb/encoding/vparquet4/compactor_test.go index 5c5fb91df29..aa811b6604a 100644 --- a/tempodb/encoding/vparquet4/compactor_test.go +++ b/tempodb/encoding/vparquet4/compactor_test.go @@ -14,7 +14,6 @@ import ( tempo_io "github.com/grafana/tempo/pkg/io" tempoUtil "github.com/grafana/tempo/pkg/util" "github.com/grafana/tempo/pkg/util/test" - "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/backend/local" "github.com/grafana/tempo/tempodb/encoding/common" @@ -113,7 +112,7 @@ func BenchmarkCompactorDupes(b *testing.B) { func createTestBlock(t testing.TB, ctx context.Context, cfg *common.BlockConfig, r backend.Reader, w backend.Writer, traceCount, batchCount, spanCount, replicationFactor int, dc backend.DedicatedColumns) *backend.BlockMeta { inMeta := &backend.BlockMeta{ TenantID: tenantID, - BlockID: uuid.New(), + BlockID: backend.NewUUID(), TotalObjects: int32(traceCount), ReplicationFactor: uint32(replicationFactor), DedicatedColumns: dc, diff --git a/tempodb/encoding/vparquet4/copy.go b/tempodb/encoding/vparquet4/copy.go index 37927fc2869..ec0a4e278ab 100644 --- a/tempodb/encoding/vparquet4/copy.go +++ b/tempodb/encoding/vparquet4/copy.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" + "github.com/google/uuid" "github.com/grafana/tempo/pkg/cache" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/encoding/common" @@ -13,25 +14,25 @@ import ( func CopyBlock(ctx context.Context, fromMeta, toMeta *backend.BlockMeta, from backend.Reader, to backend.Writer) error { // Copy streams, efficient but can't cache. copyStream := func(name string) error { - reader, size, err := from.StreamReader(ctx, name, fromMeta.BlockID.UUID, fromMeta.TenantID) + reader, size, err := from.StreamReader(ctx, name, (uuid.UUID)(fromMeta.BlockID), fromMeta.TenantID) if err != nil { return fmt.Errorf("error reading %s: %w", name, err) } defer reader.Close() - return to.StreamWriter(ctx, name, toMeta.BlockID.UUID, toMeta.TenantID, reader, size) + return to.StreamWriter(ctx, name, (uuid.UUID)(toMeta.BlockID), toMeta.TenantID, reader, size) } // Read entire object and attempt to cache cpy := func(name string, cacheInfo *backend.CacheInfo) error { cacheInfo.Meta = fromMeta - b, err := from.Read(ctx, name, fromMeta.BlockID.UUID, fromMeta.TenantID, cacheInfo) + b, err := from.Read(ctx, name, (uuid.UUID)(fromMeta.BlockID), fromMeta.TenantID, cacheInfo) if err != nil { return fmt.Errorf("error reading %s: %w", name, err) } cacheInfo.Meta = toMeta - return to.Write(ctx, name, toMeta.BlockID.UUID, toMeta.TenantID, b, cacheInfo) + return to.Write(ctx, name, (uuid.UUID)(toMeta.BlockID), toMeta.TenantID, b, cacheInfo) } // Data @@ -73,7 +74,7 @@ func writeBlockMeta(ctx context.Context, w backend.Writer, meta *backend.BlockMe } for i, bloom := range blooms { nameBloom := common.BloomName(i) - err := w.Write(ctx, nameBloom, meta.BlockID.UUID, meta.TenantID, bloom, cacheInfo) + err := w.Write(ctx, nameBloom, (uuid.UUID)(meta.BlockID), meta.TenantID, bloom, cacheInfo) if err != nil { return fmt.Errorf("unexpected error writing bloom-%d: %w", i, err) } @@ -84,7 +85,7 @@ func writeBlockMeta(ctx context.Context, w backend.Writer, meta *backend.BlockMe if err != nil { return err } - err = w.Write(ctx, common.NameIndex, meta.BlockID.UUID, meta.TenantID, i, &backend.CacheInfo{ + err = w.Write(ctx, common.NameIndex, (uuid.UUID)(meta.BlockID), meta.TenantID, i, &backend.CacheInfo{ Meta: meta, Role: cache.RoleTraceIDIdx, }) diff --git a/tempodb/encoding/vparquet4/create.go b/tempodb/encoding/vparquet4/create.go index e698e85a6e9..0067fc11ddc 100644 --- a/tempodb/encoding/vparquet4/create.go +++ b/tempodb/encoding/vparquet4/create.go @@ -107,7 +107,7 @@ type streamingBlock struct { } func newStreamingBlock(ctx context.Context, cfg *common.BlockConfig, meta *backend.BlockMeta, r backend.Reader, to backend.Writer, createBufferedWriter func(w io.Writer) tempo_io.BufferedWriteFlusher) *streamingBlock { - newMeta := backend.NewBlockMetaWithDedicatedColumns(meta.TenantID, meta.BlockID.UUID, VersionString, backend.EncNone, "", meta.DedicatedColumns) + newMeta := backend.NewBlockMetaWithDedicatedColumns(meta.TenantID, (uuid.UUID)(meta.BlockID), VersionString, backend.EncNone, "", meta.DedicatedColumns) newMeta.StartTime = meta.StartTime newMeta.EndTime = meta.EndTime newMeta.ReplicationFactor = meta.ReplicationFactor @@ -116,7 +116,7 @@ func newStreamingBlock(ctx context.Context, cfg *common.BlockConfig, meta *backe // The real number of objects is tracked below. bloom := common.NewBloom(cfg.BloomFP, uint(cfg.BloomShardSizeBytes), uint(meta.TotalObjects)) - w := &backendWriter{ctx, to, DataFileName, meta.BlockID.UUID, meta.TenantID, nil} + w := &backendWriter{ctx, to, DataFileName, (uuid.UUID)(meta.BlockID), meta.TenantID, nil} bw := createBufferedWriter(w) pw := parquet.NewGenericWriter[*Trace](bw) @@ -225,7 +225,7 @@ func (b *streamingBlock) Complete() (int, error) { // Read the footer size out of the parquet footer buf := make([]byte, 8) - err = b.r.ReadRange(b.ctx, DataFileName, b.meta.BlockID.UUID, b.meta.TenantID, b.meta.Size_-8, buf, nil) + err = b.r.ReadRange(b.ctx, DataFileName, (uuid.UUID)(b.meta.BlockID), b.meta.TenantID, b.meta.Size_-8, buf, nil) if err != nil { return 0, fmt.Errorf("error reading parquet file footer: %w", err) } diff --git a/tempodb/encoding/vparquet4/readers.go b/tempodb/encoding/vparquet4/readers.go index 9a170786ed2..4926f35d03f 100644 --- a/tempodb/encoding/vparquet4/readers.go +++ b/tempodb/encoding/vparquet4/readers.go @@ -7,6 +7,7 @@ import ( "go.uber.org/atomic" + "github.com/google/uuid" "github.com/grafana/tempo/pkg/cache" "github.com/grafana/tempo/tempodb/backend" ) @@ -37,7 +38,7 @@ func (b *BackendReaderAt) ReadAt(p []byte, off int64) (int, error) { } func (b *BackendReaderAt) ReadAtWithCache(p []byte, off int64, role cache.Role) (int, error) { - err := b.r.ReadRange(b.ctx, b.name, b.meta.BlockID.UUID, b.meta.TenantID, uint64(off), p, &backend.CacheInfo{ + err := b.r.ReadRange(b.ctx, b.name, (uuid.UUID)(b.meta.BlockID), b.meta.TenantID, uint64(off), p, &backend.CacheInfo{ Role: role, Meta: b.meta, }) diff --git a/tempodb/retention.go b/tempodb/retention.go index c56ef7c897b..fd7fd667cfd 100644 --- a/tempodb/retention.go +++ b/tempodb/retention.go @@ -5,6 +5,7 @@ import ( "time" "github.com/go-kit/log/level" + "github.com/google/uuid" "github.com/grafana/tempo/pkg/boundedwaitgroup" "github.com/grafana/tempo/tempodb/backend" @@ -66,7 +67,7 @@ func (rw *readerWriter) retainTenant(ctx context.Context, tenantID string) { default: if b.EndTime.Before(cutoff) && rw.compactorSharder.Owns(b.BlockID.String()) { level.Info(rw.logger).Log("msg", "marking block for deletion", "blockID", b.BlockID, "tenantID", tenantID) - err := rw.c.MarkBlockCompacted(b.BlockID.UUID, tenantID) + err := rw.c.MarkBlockCompacted((uuid.UUID)(b.BlockID), tenantID) if err != nil { level.Error(rw.logger).Log("msg", "failed to mark block compacted during retention", "blockID", b.BlockID, "tenantID", tenantID, "err", err) metricRetentionErrors.Inc() @@ -95,7 +96,7 @@ func (rw *readerWriter) retainTenant(ctx context.Context, tenantID string) { level.Debug(rw.logger).Log("owns", rw.compactorSharder.Owns(b.BlockID.String()), "blockID", b.BlockID, "tenantID", tenantID) if b.CompactedTime.Before(cutoff) && rw.compactorSharder.Owns(b.BlockID.String()) { level.Info(rw.logger).Log("msg", "deleting block", "blockID", b.BlockID, "tenantID", tenantID) - err := rw.c.ClearBlock(b.BlockID.UUID, tenantID) + err := rw.c.ClearBlock((uuid.UUID)(b.BlockID), tenantID) if err != nil { level.Error(rw.logger).Log("msg", "failed to clear compacted block during retention", "blockID", b.BlockID, "tenantID", tenantID, "err", err) metricRetentionErrors.Inc() diff --git a/tempodb/retention_test.go b/tempodb/retention_test.go index 588ec71508f..af5862276d1 100644 --- a/tempodb/retention_test.go +++ b/tempodb/retention_test.go @@ -7,11 +7,11 @@ import ( "time" "github.com/go-kit/log" + "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/grafana/tempo/pkg/model" - "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/backend/local" "github.com/grafana/tempo/tempodb/encoding" @@ -53,7 +53,7 @@ func TestRetention(t *testing.T) { r.EnablePolling(ctx, &mockJobSharder{}) - blockID := uuid.New() + blockID := backend.NewUUID() wal := w.WAL() assert.NoError(t, err) @@ -68,15 +68,15 @@ func TestRetention(t *testing.T) { rw := r.(*readerWriter) // poll - checkBlocklists(t, blockID.UUID, 1, 0, rw) + checkBlocklists(t, (uuid.UUID)(blockID), 1, 0, rw) // retention should mark it compacted r.(*readerWriter).doRetention(ctx) - checkBlocklists(t, blockID.UUID, 0, 1, rw) + checkBlocklists(t, (uuid.UUID)(blockID), 0, 1, rw) // retention again should clear it r.(*readerWriter).doRetention(ctx) - checkBlocklists(t, blockID.UUID, 0, 0, rw) + checkBlocklists(t, (uuid.UUID)(blockID), 0, 0, rw) } func TestRetentionUpdatesBlocklistImmediately(t *testing.T) { @@ -120,7 +120,7 @@ func TestRetentionUpdatesBlocklistImmediately(t *testing.T) { wal := w.WAL() assert.NoError(t, err) - blockID := uuid.New() + blockID := backend.NewUUID() meta := &backend.BlockMeta{BlockID: blockID, TenantID: testTenantID} head, err := wal.NewBlock(meta, model.CurrentEncoding) diff --git a/tempodb/tempodb.go b/tempodb/tempodb.go index c5ef7a427a9..d934634e15b 100644 --- a/tempodb/tempodb.go +++ b/tempodb/tempodb.go @@ -603,7 +603,7 @@ func includeBlock(b *backend.BlockMeta, _ common.ID, blockStart, blockEnd []byte } } - blockIDBytes, _ := b.BlockID.MarshalBinary() + blockIDBytes, _ := b.BlockID.Marshal() // check block is in shard boundaries // blockStartBytes <= blockIDBytes <= blockEndBytes if bytes.Compare(blockIDBytes, blockStart) == -1 || bytes.Compare(blockIDBytes, blockEnd) == 1 { diff --git a/tempodb/tempodb_search_test.go b/tempodb/tempodb_search_test.go index 07e2c8dcc7d..5c93c26975d 100644 --- a/tempodb/tempodb_search_test.go +++ b/tempodb/tempodb_search_test.go @@ -28,7 +28,6 @@ import ( "github.com/grafana/tempo/pkg/util" "github.com/grafana/tempo/pkg/util/math" "github.com/grafana/tempo/pkg/util/test" - "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/backend/local" "github.com/grafana/tempo/tempodb/encoding" @@ -1620,7 +1619,7 @@ func runCompleteBlockSearchTest(t *testing.T, blockVersion string, runners ...ru // Write to wal wal := w.WAL() - meta := &backend.BlockMeta{BlockID: uuid.New(), TenantID: testTenantID, DedicatedColumns: dc} + meta := &backend.BlockMeta{BlockID: backend.NewUUID(), TenantID: testTenantID, DedicatedColumns: dc} head, err := wal.NewBlock(meta, model.CurrentEncoding) require.NoError(t, err) dec := model.MustNewSegmentDecoder(model.CurrentEncoding) @@ -1736,7 +1735,7 @@ func runEventLinkInstrumentationSearchTest(t *testing.T, blockVersion string) { // Write to wal wal := w.WAL() - meta := &backend.BlockMeta{BlockID: uuid.New(), TenantID: testTenantID} + meta := &backend.BlockMeta{BlockID: backend.NewUUID(), TenantID: testTenantID} head, err := wal.NewBlock(meta, model.CurrentEncoding) require.NoError(t, err) dec := model.MustNewSegmentDecoder(model.CurrentEncoding) @@ -2207,7 +2206,7 @@ func TestWALBlockGetMetrics(t *testing.T) { r.EnablePolling(ctx, &mockJobSharder{}) wal := w.WAL() - meta := &backend.BlockMeta{BlockID: uuid.New(), TenantID: testTenantID} + meta := &backend.BlockMeta{BlockID: backend.NewUUID(), TenantID: testTenantID} head, err := wal.NewBlock(meta, model.CurrentEncoding) require.NoError(t, err) @@ -2265,7 +2264,7 @@ func TestSearchForTagsAndTagValues(t *testing.T) { r.EnablePolling(context.Background(), &mockJobSharder{}) - blockID := uuid.New() + blockID := backend.NewUUID() wal := w.WAL() diff --git a/tempodb/tempodb_test.go b/tempodb/tempodb_test.go index cd8aa2a2c80..d47374f9047 100644 --- a/tempodb/tempodb_test.go +++ b/tempodb/tempodb_test.go @@ -12,7 +12,7 @@ import ( "github.com/go-kit/log" "github.com/golang/protobuf/proto" //nolint:all - google_uuid "github.com/google/uuid" + "github.com/google/uuid" v2 "github.com/grafana/tempo/tempodb/encoding/v2" "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/assert" @@ -25,7 +25,6 @@ import ( "github.com/grafana/tempo/pkg/model/trace" "github.com/grafana/tempo/pkg/tempopb" "github.com/grafana/tempo/pkg/util/test" - "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/backend/local" "github.com/grafana/tempo/tempodb/encoding" @@ -88,7 +87,7 @@ func TestDB(t *testing.T) { r.EnablePolling(context.Background(), &mockJobSharder{}) - blockID := uuid.New() + blockID := backend.NewUUID() wal := w.WAL() @@ -141,7 +140,7 @@ func TestBlockSharding(t *testing.T) { r.EnablePolling(context.Background(), &mockJobSharder{}) // create block with known ID - blockID := uuid.New() + blockID := backend.NewUUID() wal := w.WAL() dec := model.MustNewSegmentDecoder(model.CurrentEncoding) @@ -166,8 +165,8 @@ func TestBlockSharding(t *testing.T) { assert.Len(t, blocks, 1) // check if it respects the blockstart/blockend params - case1: hit - blockStart := google_uuid.MustParse(BlockIDMin).String() - blockEnd := google_uuid.MustParse(BlockIDMax).String() + blockStart := uuid.MustParse(BlockIDMin).String() + blockEnd := uuid.MustParse(BlockIDMax).String() bFound, failedBlocks, err := r.Find(context.Background(), testTenantID, id, blockStart, blockEnd, 0, 0, common.DefaultSearchOptions()) assert.NoError(t, err) assert.Nil(t, failedBlocks) @@ -175,8 +174,8 @@ func TestBlockSharding(t *testing.T) { assert.True(t, proto.Equal(bFound[0], req)) // check if it respects the blockstart/blockend params - case2: miss - blockStart = google_uuid.MustParse(BlockIDMin).String() - blockEnd = google_uuid.MustParse(BlockIDMin).String() + blockStart = uuid.MustParse(BlockIDMin).String() + blockEnd = uuid.MustParse(BlockIDMin).String() bFound, failedBlocks, err = r.Find(context.Background(), testTenantID, id, blockStart, blockEnd, 0, 0, common.DefaultSearchOptions()) assert.NoError(t, err) assert.Nil(t, failedBlocks) @@ -205,7 +204,7 @@ func TestBlockCleanup(t *testing.T) { r.EnablePolling(context.Background(), &mockJobSharder{}) - blockID := uuid.New() + blockID := backend.NewUUID() wal := w.WAL() @@ -232,13 +231,13 @@ func TestBlockCleanup(t *testing.T) { assert.Equal(t, 0, len(m)) } -func checkBlocklists(t *testing.T, expectedID google_uuid.UUID, expectedB int, expectedCB int, rw *readerWriter) { +func checkBlocklists(t *testing.T, expectedID uuid.UUID, expectedB int, expectedCB int, rw *readerWriter) { rw.pollBlocklist() blocklist := rw.blocklist.Metas(testTenantID) require.Len(t, blocklist, expectedB) - if expectedB > 0 && expectedID != google_uuid.Nil { - assert.Equal(t, expectedID, blocklist[0].BlockID.UUID) + if expectedB > 0 && expectedID != uuid.Nil { + assert.Equal(t, expectedID, (uuid.UUID)(blocklist[0].BlockID)) } // confirm blocklists are in starttime ascending order @@ -250,8 +249,8 @@ func checkBlocklists(t *testing.T, expectedID google_uuid.UUID, expectedB int, e compactedBlocklist := rw.blocklist.CompactedMetas(testTenantID) assert.Len(t, compactedBlocklist, expectedCB) - if expectedCB > 0 && expectedID != google_uuid.Nil { - assert.Equal(t, expectedID, compactedBlocklist[0].BlockID.UUID) + if expectedCB > 0 && expectedID != uuid.Nil { + assert.Equal(t, expectedID, (uuid.UUID)(compactedBlocklist[0].BlockID)) } lastTime = time.Time{} @@ -265,8 +264,8 @@ func TestIncludeBlock(t *testing.T) { tests := []struct { name string searchID common.ID - blockStart google_uuid.UUID - blockEnd google_uuid.UUID + blockStart uuid.UUID + blockEnd uuid.UUID start int64 end int64 meta *backend.BlockMeta @@ -276,10 +275,10 @@ func TestIncludeBlock(t *testing.T) { { name: "include - duh", searchID: []byte{0x05}, - blockStart: google_uuid.MustParse(BlockIDMin), - blockEnd: google_uuid.MustParse(BlockIDMax), + blockStart: uuid.MustParse(BlockIDMin), + blockEnd: uuid.MustParse(BlockIDMax), meta: &backend.BlockMeta{ - BlockID: uuid.MustParse("50000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("50000000-0000-0000-0000-000000000000"), }, start: 0, end: 0, @@ -288,10 +287,10 @@ func TestIncludeBlock(t *testing.T) { { name: "include - min id range", searchID: []byte{0x00}, - blockStart: google_uuid.MustParse(BlockIDMin), - blockEnd: google_uuid.MustParse(BlockIDMax), + blockStart: uuid.MustParse(BlockIDMin), + blockEnd: uuid.MustParse(BlockIDMax), meta: &backend.BlockMeta{ - BlockID: uuid.MustParse("50000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("50000000-0000-0000-0000-000000000000"), }, start: 0, end: 0, @@ -300,10 +299,10 @@ func TestIncludeBlock(t *testing.T) { { name: "include - max id range", searchID: []byte{0x10}, - blockStart: google_uuid.MustParse(BlockIDMin), - blockEnd: google_uuid.MustParse(BlockIDMax), + blockStart: uuid.MustParse(BlockIDMin), + blockEnd: uuid.MustParse(BlockIDMax), meta: &backend.BlockMeta{ - BlockID: uuid.MustParse("50000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("50000000-0000-0000-0000-000000000000"), }, start: 0, end: 0, @@ -312,10 +311,10 @@ func TestIncludeBlock(t *testing.T) { { name: "include - min block range", searchID: []byte{0x05}, - blockStart: google_uuid.MustParse("50000000-0000-0000-0000-000000000000"), - blockEnd: google_uuid.MustParse(BlockIDMax), + blockStart: uuid.MustParse("50000000-0000-0000-0000-000000000000"), + blockEnd: uuid.MustParse(BlockIDMax), meta: &backend.BlockMeta{ - BlockID: uuid.MustParse("50000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("50000000-0000-0000-0000-000000000000"), }, start: 0, end: 0, @@ -324,10 +323,10 @@ func TestIncludeBlock(t *testing.T) { { name: "include - max block range", searchID: []byte{0x05}, - blockStart: google_uuid.MustParse(BlockIDMin), - blockEnd: google_uuid.MustParse("50000000-0000-0000-0000-000000000000"), + blockStart: uuid.MustParse(BlockIDMin), + blockEnd: uuid.MustParse("50000000-0000-0000-0000-000000000000"), meta: &backend.BlockMeta{ - BlockID: uuid.MustParse("50000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("50000000-0000-0000-0000-000000000000"), StartTime: time.Unix(10000, 0), EndTime: time.Unix(20000, 0), }, @@ -338,10 +337,10 @@ func TestIncludeBlock(t *testing.T) { { name: "include - max block range", searchID: []byte{0x05}, - blockStart: google_uuid.MustParse(BlockIDMin), - blockEnd: google_uuid.MustParse("50000000-0000-0000-0000-000000000000"), + blockStart: uuid.MustParse(BlockIDMin), + blockEnd: uuid.MustParse("50000000-0000-0000-0000-000000000000"), meta: &backend.BlockMeta{ - BlockID: uuid.MustParse("50000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("50000000-0000-0000-0000-000000000000"), StartTime: time.Unix(1650285326, 0), EndTime: time.Unix(1650288990, 0), }, @@ -352,10 +351,10 @@ func TestIncludeBlock(t *testing.T) { { name: "include - exact hit", searchID: []byte{0x05}, - blockStart: google_uuid.MustParse("50000000-0000-0000-0000-000000000000"), - blockEnd: google_uuid.MustParse("50000000-0000-0000-0000-000000000000"), + blockStart: uuid.MustParse("50000000-0000-0000-0000-000000000000"), + blockEnd: uuid.MustParse("50000000-0000-0000-0000-000000000000"), meta: &backend.BlockMeta{ - BlockID: uuid.MustParse("50000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("50000000-0000-0000-0000-000000000000"), }, start: 0, end: 0, @@ -365,10 +364,10 @@ func TestIncludeBlock(t *testing.T) { { name: "exclude - duh", searchID: []byte{0x20}, - blockStart: google_uuid.MustParse("50000000-0000-0000-0000-000000000000"), - blockEnd: google_uuid.MustParse("51000000-0000-0000-0000-000000000000"), + blockStart: uuid.MustParse("50000000-0000-0000-0000-000000000000"), + blockEnd: uuid.MustParse("51000000-0000-0000-0000-000000000000"), meta: &backend.BlockMeta{ - BlockID: uuid.MustParse("52000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("52000000-0000-0000-0000-000000000000"), }, }, // todo: restore when this is fixed: https://github.com/grafana/tempo/issues/1903 @@ -393,19 +392,19 @@ func TestIncludeBlock(t *testing.T) { { name: "exclude - min block range", searchID: []byte{0x05}, - blockStart: google_uuid.MustParse("50000000-0000-0000-0000-000000000000"), - blockEnd: google_uuid.MustParse("51000000-0000-0000-0000-000000000000"), + blockStart: uuid.MustParse("50000000-0000-0000-0000-000000000000"), + blockEnd: uuid.MustParse("51000000-0000-0000-0000-000000000000"), meta: &backend.BlockMeta{ - BlockID: uuid.MustParse("4FFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF"), + BlockID: backend.MustParse("4FFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF"), }, }, { name: "exclude - max block range", searchID: []byte{0x05}, - blockStart: google_uuid.MustParse("50000000-0000-0000-0000-000000000000"), - blockEnd: google_uuid.MustParse("51000000-0000-0000-0000-000000000000"), + blockStart: uuid.MustParse("50000000-0000-0000-0000-000000000000"), + blockEnd: uuid.MustParse("51000000-0000-0000-0000-000000000000"), meta: &backend.BlockMeta{ - BlockID: uuid.MustParse("51000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("51000000-0000-0000-0000-000000000001"), }, }, } @@ -427,8 +426,8 @@ func TestIncludeCompactedBlock(t *testing.T) { tests := []struct { name string searchID common.ID - blockStart google_uuid.UUID - blockEnd google_uuid.UUID + blockStart uuid.UUID + blockEnd uuid.UUID meta *backend.CompactedBlockMeta start int64 end int64 @@ -437,13 +436,13 @@ func TestIncludeCompactedBlock(t *testing.T) { { name: "include recent", searchID: []byte{0x05}, - blockStart: google_uuid.MustParse(BlockIDMin), - blockEnd: google_uuid.MustParse(BlockIDMax), + blockStart: uuid.MustParse(BlockIDMin), + blockEnd: uuid.MustParse(BlockIDMax), start: 0, end: 0, meta: &backend.CompactedBlockMeta{ BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("50000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("50000000-0000-0000-0000-000000000000"), }, CompactedTime: time.Now().Add(-(1 * blocklistPoll)), }, @@ -452,13 +451,13 @@ func TestIncludeCompactedBlock(t *testing.T) { { name: "skip old", searchID: []byte{0x05}, - blockStart: google_uuid.MustParse(BlockIDMin), - blockEnd: google_uuid.MustParse(BlockIDMax), + blockStart: uuid.MustParse(BlockIDMin), + blockEnd: uuid.MustParse(BlockIDMax), start: 0, end: 0, meta: &backend.CompactedBlockMeta{ BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("50000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("50000000-0000-0000-0000-000000000000"), }, CompactedTime: time.Now().Add(-(3 * blocklistPoll)), }, @@ -467,13 +466,13 @@ func TestIncludeCompactedBlock(t *testing.T) { { name: "skip recent but out of range", searchID: []byte{0x05}, - blockStart: google_uuid.MustParse("40000000-0000-0000-0000-000000000000"), - blockEnd: google_uuid.MustParse("50000000-0000-0000-0000-000000000000"), + blockStart: uuid.MustParse("40000000-0000-0000-0000-000000000000"), + blockEnd: uuid.MustParse("50000000-0000-0000-0000-000000000000"), start: 0, end: 0, meta: &backend.CompactedBlockMeta{ BlockMeta: backend.BlockMeta{ - BlockID: uuid.MustParse("51000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("51000000-0000-0000-0000-000000000000"), }, CompactedTime: time.Now().Add(-(1 * blocklistPoll)), }, @@ -508,7 +507,7 @@ func TestSearchCompactedBlocks(t *testing.T) { wal := w.WAL() - meta := &backend.BlockMeta{BlockID: uuid.New(), TenantID: testTenantID} + meta := &backend.BlockMeta{BlockID: backend.NewUUID(), TenantID: testTenantID} head, err := wal.NewBlock(meta, model.CurrentEncoding) assert.NoError(t, err) @@ -589,7 +588,7 @@ func testCompleteBlock(t *testing.T, from, to string) { rw := w.(*readerWriter) rw.cfg.Block.Version = to // now set it back so we cut blocks in the "to" format - blockID := google_uuid.New() + blockID := uuid.New() var dataEncoding string if from == v2.VersionString { @@ -669,7 +668,7 @@ func testCompleteBlockHonorsStartStopTimes(t *testing.T, targetBlockVersion stri oneHourAgo := now.Add(-1 * time.Hour).Unix() oneHour := now.Add(time.Hour).Unix() - meta := &backend.BlockMeta{BlockID: uuid.New(), TenantID: testTenantID} + meta := &backend.BlockMeta{BlockID: backend.NewUUID(), TenantID: testTenantID} block, err := wal.NewBlock(meta, model.CurrentEncoding) require.NoError(t, err, "unexpected error creating block") @@ -738,7 +737,7 @@ func benchmarkCompleteBlock(b *testing.B, e encoding.VersionedEncoding) { dec := model.MustNewSegmentDecoder(model.CurrentEncoding) wal := w.WAL() - meta := &backend.BlockMeta{BlockID: uuid.New(), TenantID: testTenantID} + meta := &backend.BlockMeta{BlockID: backend.NewUUID(), TenantID: testTenantID} blk, err := wal.NewBlock(meta, model.CurrentEncoding) require.NoError(b, err) From 5f36d86a0500962b9ca6023aa18af6de057b942b Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Mon, 23 Sep 2024 20:33:21 +0000 Subject: [PATCH 40/71] Re-plumb UUID through cmd --- cmd/tempo-cli/cmd-migrate-tenant.go | 3 ++- cmd/tempo-cli/cmd-rewrite-blocks.go | 2 +- cmd/tempo-cli/shared.go | 14 +++++++------- cmd/tempo-serverless/handler.go | 3 +-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cmd/tempo-cli/cmd-migrate-tenant.go b/cmd/tempo-cli/cmd-migrate-tenant.go index 7386051e9bc..e59874fe390 100644 --- a/cmd/tempo-cli/cmd-migrate-tenant.go +++ b/cmd/tempo-cli/cmd-migrate-tenant.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/dustin/go-humanize" + "github.com/google/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/encoding" @@ -49,7 +50,7 @@ blocks: for _, sourceBlockMeta := range sourceTenantIndex.Meta { // check for collisions for _, uuidDest := range blocksDest { - if sourceBlockMeta.BlockID.UUID == uuidDest { + if (uuid.UUID)(sourceBlockMeta.BlockID) == uuidDest { fmt.Printf("UUID %s exists in source and destination, skipping block\n", sourceBlockMeta.BlockID) continue blocks } diff --git a/cmd/tempo-cli/cmd-rewrite-blocks.go b/cmd/tempo-cli/cmd-rewrite-blocks.go index 6e6c8ffb719..ea5f22069be 100644 --- a/cmd/tempo-cli/cmd-rewrite-blocks.go +++ b/cmd/tempo-cli/cmd-rewrite-blocks.go @@ -82,7 +82,7 @@ func (cmd *dropTraceCmd) Run(ctx *globalOptions) error { fmt.Println("marking old blocks compacted") for _, block := range blocks { fmt.Printf(" marking %v\n", block.BlockID) - err = c.MarkBlockCompacted(block.BlockID.UUID, block.TenantID) + err = c.MarkBlockCompacted((uuid.UUID)(block.BlockID), block.TenantID) if err != nil { return err } diff --git a/cmd/tempo-cli/shared.go b/cmd/tempo-cli/shared.go index 092512dfa27..1bd13a3df60 100644 --- a/cmd/tempo-cli/shared.go +++ b/cmd/tempo-cli/shared.go @@ -9,8 +9,8 @@ import ( "strconv" "time" + "github.com/google/uuid" "github.com/grafana/tempo/pkg/boundedwaitgroup" - "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" ) @@ -41,7 +41,7 @@ func getMeta(meta *backend.BlockMeta, compactedMeta *backend.CompactedBlockMeta, return unifiedBlockMeta{ BlockMeta: backend.BlockMeta{ - BlockID: uuid.UUID{}, + BlockID: backend.UUID{}, CompactionLevel: 0, TotalObjects: -1, }, @@ -71,7 +71,7 @@ func loadBucket(r backend.Reader, c backend.Compactor, tenantID string, windowRa for blockNum, id := range blockIDs { wg.Add(1) - go func(id2 uuid.UUID, blockNum2 int) { + go func(id2 backend.UUID, blockNum2 int) { defer wg.Done() b, err := loadBlock(r, c, tenantID, id2, blockNum2, windowRange, includeCompacted) @@ -83,7 +83,7 @@ func loadBucket(r backend.Reader, c backend.Compactor, tenantID string, windowRa if b != nil { resultsCh <- *b } - }(uuid.From(id), blockNum) + }(backend.UUID(id), blockNum) } wg.Wait() @@ -101,20 +101,20 @@ func loadBucket(r backend.Reader, c backend.Compactor, tenantID string, windowRa return results, nil } -func loadBlock(r backend.Reader, c backend.Compactor, tenantID string, id uuid.UUID, blockNum int, windowRange time.Duration, includeCompacted bool) (*blockStats, error) { +func loadBlock(r backend.Reader, c backend.Compactor, tenantID string, id backend.UUID, blockNum int, windowRange time.Duration, includeCompacted bool) (*blockStats, error) { fmt.Print(".") if blockNum%100 == 0 { fmt.Print(strconv.Itoa(blockNum)) } - meta, err := r.BlockMeta(context.Background(), id.UUID, tenantID) + meta, err := r.BlockMeta(context.Background(), (uuid.UUID)(id), tenantID) if errors.Is(err, backend.ErrDoesNotExist) && !includeCompacted { return nil, nil } else if err != nil && !errors.Is(err, backend.ErrDoesNotExist) { return nil, err } - compactedMeta, err := c.CompactedBlockMeta(id.UUID, tenantID) + compactedMeta, err := c.CompactedBlockMeta((uuid.UUID)(id), tenantID) if err != nil && !errors.Is(err, backend.ErrDoesNotExist) { return nil, err } diff --git a/cmd/tempo-serverless/handler.go b/cmd/tempo-serverless/handler.go index 0a7f0efe9ec..13a877a1fc5 100644 --- a/cmd/tempo-serverless/handler.go +++ b/cmd/tempo-serverless/handler.go @@ -19,7 +19,6 @@ import ( "github.com/grafana/tempo/pkg/api" "github.com/grafana/tempo/pkg/tempopb" "github.com/grafana/tempo/pkg/traceql" - "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/backend/azure" @@ -71,7 +70,7 @@ func Handler(r *http.Request) (*tempopb.SearchResponse, *HTTPError) { return nil, httpError("extracting org id", err, http.StatusBadRequest) } - blockID, err := uuid.Parse(searchReq.BlockID) + blockID, err := backend.ParseUUID(searchReq.BlockID) if err != nil { return nil, httpError("parsing uuid", err, http.StatusBadRequest) } From eb0f3cc4970dbed9ccf647ac54a223704c1e08f2 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Mon, 23 Sep 2024 20:34:45 +0000 Subject: [PATCH 41/71] Re-plumb UUID through modules --- modules/frontend/cache_keys_test.go | 17 +++++---- modules/frontend/search_handlers_test.go | 13 ++++--- modules/frontend/search_sharder_test.go | 24 ++++++------- modules/frontend/tag_handlers_test.go | 3 +- .../processor/localblocks/processor.go | 29 ++++++++------- .../processor/localblocks/query_range.go | 5 +-- modules/ingester/ingester.go | 7 ++-- modules/ingester/instance.go | 35 +++++++++---------- modules/ingester/instance_search.go | 6 ++-- modules/ingester/local_block.go | 5 +-- modules/querier/querier.go | 9 +++-- modules/querier/querier_query_range.go | 3 +- 12 files changed, 76 insertions(+), 80 deletions(-) diff --git a/modules/frontend/cache_keys_test.go b/modules/frontend/cache_keys_test.go index d875a3966dd..29addd2af2d 100644 --- a/modules/frontend/cache_keys_test.go +++ b/modules/frontend/cache_keys_test.go @@ -5,7 +5,6 @@ import ( "time" "github.com/grafana/tempo/pkg/tempopb" - "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/stretchr/testify/require" ) @@ -31,7 +30,7 @@ func TestCacheKeyForJob(t *testing.T) { End: 20, }, meta: &backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000123"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000123"), StartTime: time.Unix(15, 0), EndTime: time.Unix(16, 0), }, @@ -47,7 +46,7 @@ func TestCacheKeyForJob(t *testing.T) { End: 20, }, meta: &backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000123"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000123"), StartTime: time.Unix(15, 0), EndTime: time.Unix(16, 0), }, @@ -63,7 +62,7 @@ func TestCacheKeyForJob(t *testing.T) { End: 20, }, meta: &backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000123"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000123"), StartTime: time.Unix(5, 0), EndTime: time.Unix(6, 0), }, @@ -79,7 +78,7 @@ func TestCacheKeyForJob(t *testing.T) { End: 20, }, meta: &backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000123"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000123"), StartTime: time.Unix(5, 0), EndTime: time.Unix(15, 0), }, @@ -95,7 +94,7 @@ func TestCacheKeyForJob(t *testing.T) { End: 20, }, meta: &backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000123"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000123"), StartTime: time.Unix(15, 0), EndTime: time.Unix(25, 0), }, @@ -111,7 +110,7 @@ func TestCacheKeyForJob(t *testing.T) { End: 20, }, meta: &backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000123"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000123"), StartTime: time.Unix(25, 0), EndTime: time.Unix(30, 0), }, @@ -127,7 +126,7 @@ func TestCacheKeyForJob(t *testing.T) { End: 20, }, meta: &backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000123"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000123"), StartTime: time.Unix(5, 0), EndTime: time.Unix(30, 0), }, @@ -151,7 +150,7 @@ func BenchmarkCacheKeyForJob(b *testing.B) { End: 20, } meta := &backend.BlockMeta{ - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000123"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000123"), StartTime: time.Unix(15, 0), EndTime: time.Unix(16, 0), } diff --git a/modules/frontend/search_handlers_test.go b/modules/frontend/search_handlers_test.go index 935dfee1d93..b81ff9f40d6 100644 --- a/modules/frontend/search_handlers_test.go +++ b/modules/frontend/search_handlers_test.go @@ -33,7 +33,6 @@ import ( "github.com/grafana/tempo/pkg/traceql" "github.com/grafana/tempo/pkg/util" "github.com/grafana/tempo/pkg/util/test" - "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb" "github.com/grafana/tempo/tempodb/backend" ) @@ -560,7 +559,7 @@ func TestSearchAccessesCache(t *testing.T) { EndTime: time.Unix(16, 0), Size_: defaultTargetBytesPerRequest, TotalRecords: 1, - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000123"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000123"), } rdr := &mockReader{ @@ -678,7 +677,7 @@ func BenchmarkSearchPipeline(b *testing.B) { EndTime: time.Unix(16, 0), Size_: defaultTargetBytesPerRequest, TotalRecords: 1, - BlockID: uuid.MustParse(fmt.Sprintf("00000000-0000-0000-0000-%012d", i)), + BlockID: backend.MustParse(fmt.Sprintf("00000000-0000-0000-0000-%012d", i)), }) } @@ -737,14 +736,14 @@ func frontendWithSettings(t require.TestingT, next http.RoundTripper, rdr tempod EndTime: time.Unix(1200, 0), Size_: defaultTargetBytesPerRequest * 2, TotalRecords: 2, - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000000"), }, { StartTime: time.Unix(1100, 0), EndTime: time.Unix(1200, 0), Size_: defaultTargetBytesPerRequest * 2, TotalRecords: 2, - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, // These are RF1 metrics blocks { @@ -752,7 +751,7 @@ func frontendWithSettings(t require.TestingT, next http.RoundTripper, rdr tempod EndTime: time.Unix(1200, 0), Size_: defaultTargetBytesPerRequest * 2, TotalRecords: 2, - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000002"), ReplicationFactor: 1, }, { @@ -760,7 +759,7 @@ func frontendWithSettings(t require.TestingT, next http.RoundTripper, rdr tempod EndTime: time.Unix(1200, 0), Size_: defaultTargetBytesPerRequest * 2, TotalRecords: 2, - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000003"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000003"), ReplicationFactor: 1, }, }, diff --git a/modules/frontend/search_sharder_test.go b/modules/frontend/search_sharder_test.go index 9329f73ef13..e38e587a7ce 100644 --- a/modules/frontend/search_sharder_test.go +++ b/modules/frontend/search_sharder_test.go @@ -16,6 +16,7 @@ import ( "github.com/go-kit/log" "github.com/gogo/protobuf/jsonpb" + "github.com/google/uuid" "github.com/grafana/dskit/user" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/common/model" @@ -28,7 +29,6 @@ import ( "github.com/grafana/tempo/pkg/api" "github.com/grafana/tempo/pkg/tempopb" "github.com/grafana/tempo/pkg/traceql" - "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/blocklist" @@ -96,7 +96,7 @@ func TestBuildBackendRequests(t *testing.T) { { metas: []*backend.BlockMeta{ { - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000000"), }, }, expectedURIs: []string{}, @@ -106,7 +106,7 @@ func TestBuildBackendRequests(t *testing.T) { metas: []*backend.BlockMeta{ { Size_: 1000, - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000000"), }, }, expectedURIs: []string{}, @@ -118,7 +118,7 @@ func TestBuildBackendRequests(t *testing.T) { { Size_: 1000, TotalRecords: 100, - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000000"), DataEncoding: "json", Encoding: backend.EncGZIP, IndexPageSize: 13, @@ -136,7 +136,7 @@ func TestBuildBackendRequests(t *testing.T) { { Size_: 1000, TotalRecords: 10, - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000000"), Encoding: backend.EncNone, IndexPageSize: 13, Version: "vParquet3", @@ -156,7 +156,7 @@ func TestBuildBackendRequests(t *testing.T) { { Size_: 1000, TotalRecords: 3, - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000000"), }, }, expectedURIs: []string{ @@ -172,7 +172,7 @@ func TestBuildBackendRequests(t *testing.T) { { Size_: 1000, TotalRecords: 100, - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000000"), }, }, expectedURIs: []string{ @@ -186,7 +186,7 @@ func TestBuildBackendRequests(t *testing.T) { { Size_: 1000, TotalRecords: 100, - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000000"), }, }, expectedURIs: []string{ @@ -201,12 +201,12 @@ func TestBuildBackendRequests(t *testing.T) { { Size_: 1000, TotalRecords: 100, - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000000"), }, { Size_: 1000, TotalRecords: 200, - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000001"), }, }, expectedURIs: []string{ @@ -244,7 +244,7 @@ func TestBuildBackendRequests(t *testing.T) { } func TestBackendRequests(t *testing.T) { - bm := backend.NewBlockMeta("test", uuid.New().UUID, "wdwad", backend.EncGZIP, "asdf") + bm := backend.NewBlockMeta("test", uuid.New(), "wdwad", backend.EncGZIP, "asdf") bm.StartTime = time.Unix(100, 0) bm.EndTime = time.Unix(200, 0) bm.Size_ = defaultTargetBytesPerRequest * 2 @@ -665,7 +665,7 @@ func TestTotalJobsIncludesIngester(t *testing.T) { EndTime: time.Unix(now, 0), Size_: defaultTargetBytesPerRequest * 2, TotalRecords: 2, - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000000"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000000"), }, }, }, o, SearchSharderConfig{ diff --git a/modules/frontend/tag_handlers_test.go b/modules/frontend/tag_handlers_test.go index 9fd3174c6fd..08b64bac08d 100644 --- a/modules/frontend/tag_handlers_test.go +++ b/modules/frontend/tag_handlers_test.go @@ -18,7 +18,6 @@ import ( "github.com/grafana/tempo/pkg/cache" "github.com/grafana/tempo/pkg/tempopb" "github.com/grafana/tempo/pkg/util/test" - "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/segmentio/fasthash/fnv1a" "github.com/stretchr/testify/require" @@ -434,7 +433,7 @@ func TestSearchTagsV2AccessesCache(t *testing.T) { EndTime: time.Unix(16, 0), Size_: defaultTargetBytesPerRequest, TotalRecords: 1, - BlockID: uuid.MustParse("00000000-0000-0000-0000-000000000123"), + BlockID: backend.MustParse("00000000-0000-0000-0000-000000000123"), } rdr := &mockReader{ diff --git a/modules/generator/processor/localblocks/processor.go b/modules/generator/processor/localblocks/processor.go index e1e0e43a14b..d2ad9bd7e44 100644 --- a/modules/generator/processor/localblocks/processor.go +++ b/modules/generator/processor/localblocks/processor.go @@ -13,7 +13,7 @@ import ( kitlog "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/golang/groupcache/lru" - google_uuid "github.com/google/uuid" + "github.com/google/uuid" "github.com/grafana/tempo/modules/ingester" "github.com/grafana/tempo/pkg/flushqueues" "github.com/grafana/tempo/tempodb" @@ -26,7 +26,6 @@ import ( "github.com/grafana/tempo/pkg/traceql" "github.com/grafana/tempo/pkg/traceqlmetrics" "github.com/grafana/tempo/pkg/util/log" - "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/encoding" "github.com/grafana/tempo/tempodb/encoding/common" @@ -60,8 +59,8 @@ type Processor struct { blocksMtx sync.RWMutex headBlock common.WALBlock - walBlocks map[google_uuid.UUID]common.WALBlock - completeBlocks map[google_uuid.UUID]*ingester.LocalBlock + walBlocks map[uuid.UUID]common.WALBlock + completeBlocks map[uuid.UUID]*ingester.LocalBlock lastCutTime time.Time flushqueue *flushqueues.PriorityQueue @@ -97,8 +96,8 @@ func New(cfg Config, tenant string, wal *wal.WAL, writer tempodb.Writer, overrid walW: backend.NewWriter(wal.LocalBackend()), overrides: overrides, enc: enc, - walBlocks: map[google_uuid.UUID]common.WALBlock{}, - completeBlocks: map[google_uuid.UUID]*ingester.LocalBlock{}, + walBlocks: map[uuid.UUID]common.WALBlock{}, + completeBlocks: map[uuid.UUID]*ingester.LocalBlock{}, flushqueue: flushqueues.NewPriorityQueue(metricFlushQueueSize.WithLabelValues(tenant)), liveTraces: newLiveTraces(), traceSizes: newTraceSizes(), @@ -352,11 +351,11 @@ func (p *Processor) completeBlock() error { p.blocksMtx.Lock() defer p.blocksMtx.Unlock() - p.completeBlocks[newMeta.BlockID.UUID] = ingester.NewLocalBlock(ctx, newBlock, p.wal.LocalBackend()) + p.completeBlocks[(uuid.UUID)(newMeta.BlockID)] = ingester.NewLocalBlock(ctx, newBlock, p.wal.LocalBackend()) metricCompletedBlocks.WithLabelValues(p.tenant).Inc() // Queue for flushing - if _, err := p.flushqueue.Enqueue(newFlushOp(newMeta.BlockID.UUID)); err != nil { + if _, err := p.flushqueue.Enqueue(newFlushOp((uuid.UUID)(newMeta.BlockID))); err != nil { _ = level.Error(p.logger).Log("msg", "local blocks processor failed to enqueue block for flushing", "err", err) } @@ -364,12 +363,12 @@ func (p *Processor) completeBlock() error { if err != nil { return err } - delete(p.walBlocks, b.BlockMeta().BlockID.UUID) + delete(p.walBlocks, (uuid.UUID)(b.BlockMeta().BlockID)) return nil } -func (p *Processor) flushBlock(id google_uuid.UUID) error { +func (p *Processor) flushBlock(id uuid.UUID) error { p.blocksMtx.RLock() completeBlock := p.completeBlocks[id] p.blocksMtx.RUnlock() @@ -645,7 +644,7 @@ func (p *Processor) writeHeadBlock(id common.ID, tr *tempopb.Trace) error { func (p *Processor) resetHeadBlock() error { meta := &backend.BlockMeta{ - BlockID: uuid.New(), + BlockID: backend.NewUUID(), TenantID: p.tenant, DedicatedColumns: p.overrides.DedicatedColumns(p.tenant), ReplicationFactor: backend.MetricsGeneratorReplicationFactor, @@ -680,7 +679,7 @@ func (p *Processor) cutBlocks(immediate bool) error { return fmt.Errorf("failed to flush head block: %w", err) } - p.walBlocks[p.headBlock.BlockMeta().BlockID.UUID] = p.headBlock + p.walBlocks[(uuid.UUID)(p.headBlock.BlockMeta().BlockID)] = p.headBlock metricCutBlocks.WithLabelValues(p.tenant).Inc() err = p.resetHeadBlock() @@ -711,7 +710,7 @@ func (p *Processor) reloadBlocks() error { meta := blk.BlockMeta() if meta.TenantID == p.tenant { level.Info(p.logger).Log("msg", "reloading wal block", "block", meta.BlockID.String()) - p.walBlocks[blk.BlockMeta().BlockID.UUID] = blk + p.walBlocks[(uuid.UUID)(blk.BlockMeta().BlockID)] = blk } } level.Info(p.logger).Log("msg", "reloaded wal blocks", "count", len(p.walBlocks)) @@ -879,13 +878,13 @@ func filterBatches(batches []*v1.ResourceSpans) []*v1.ResourceSpans { } type flushOp struct { - blockID google_uuid.UUID + blockID uuid.UUID at time.Time // When to execute attempts int bo time.Duration } -func newFlushOp(blockID google_uuid.UUID) *flushOp { +func newFlushOp(blockID uuid.UUID) *flushOp { return &flushOp{ blockID: blockID, at: time.Now(), diff --git a/modules/generator/processor/localblocks/query_range.go b/modules/generator/processor/localblocks/query_range.go index 23b64b358ef..848a78f9716 100644 --- a/modules/generator/processor/localblocks/query_range.go +++ b/modules/generator/processor/localblocks/query_range.go @@ -7,6 +7,7 @@ import ( "sync" "time" + "github.com/google/uuid" "github.com/segmentio/fasthash/fnv1a" "github.com/gogo/protobuf/proto" @@ -224,7 +225,7 @@ func (p *Processor) queryRangeCacheGet(ctx context.Context, m *backend.BlockMeta name := fmt.Sprintf("cache_query_range_%v.buf", hash) - data, err := p.walR.Read(ctx, name, m.BlockID.UUID, m.TenantID, nil) + data, err := p.walR.Read(ctx, name, (uuid.UUID)(m.BlockID), m.TenantID, nil) if err != nil { if errors.Is(err, backend.ErrDoesNotExist) { // Not cached, but return the name/keypath so it can be set after @@ -248,7 +249,7 @@ func (p *Processor) queryRangeCacheSet(ctx context.Context, m *backend.BlockMeta return err } - return p.walW.Write(ctx, name, m.BlockID.UUID, m.TenantID, data, nil) + return p.walW.Write(ctx, name, (uuid.UUID)(m.BlockID), m.TenantID, data, nil) } func queryRangeHashForBlock(req tempopb.QueryRangeRequest) uint64 { diff --git a/modules/ingester/ingester.go b/modules/ingester/ingester.go index e27cc7a5bf6..07c9eec0a04 100644 --- a/modules/ingester/ingester.go +++ b/modules/ingester/ingester.go @@ -10,6 +10,7 @@ import ( "github.com/go-kit/log/level" "github.com/gogo/status" + "github.com/google/uuid" "github.com/grafana/dskit/ring" "github.com/grafana/dskit/services" "github.com/grafana/dskit/user" @@ -389,7 +390,7 @@ func (i *Ingester) replayWal() error { // deleted (because it was rescanned above). This can happen for reasons // such as a crash or restart. In this situation we err on the side of // caution and replay the wal block. - err = instance.local.ClearBlock(b.BlockMeta().BlockID.UUID, tenantID) + err = instance.local.ClearBlock((uuid.UUID)(b.BlockMeta().BlockID), tenantID) if err != nil { return err } @@ -398,7 +399,7 @@ func (i *Ingester) replayWal() error { i.enqueue(&flushOp{ kind: opKindComplete, userID: tenantID, - blockID: b.BlockMeta().BlockID.UUID, + blockID: (uuid.UUID)(b.BlockMeta().BlockID), }, i.replayJitter) } @@ -445,7 +446,7 @@ func (i *Ingester) rediscoverLocalBlocks() error { i.enqueue(&flushOp{ kind: opKindFlush, userID: t, - blockID: b.BlockMeta().BlockID.UUID, + blockID: (uuid.UUID)(b.BlockMeta().BlockID), }, i.replayJitter) } } diff --git a/modules/ingester/instance.go b/modules/ingester/instance.go index 9408374c04d..0614a58d3cf 100644 --- a/modules/ingester/instance.go +++ b/modules/ingester/instance.go @@ -14,7 +14,7 @@ import ( "github.com/go-kit/log/level" "github.com/gogo/status" - google_uuid "github.com/google/uuid" + "github.com/google/uuid" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "go.uber.org/atomic" @@ -25,7 +25,6 @@ import ( "github.com/grafana/tempo/pkg/model/trace" "github.com/grafana/tempo/pkg/tempopb" "github.com/grafana/tempo/pkg/util/log" - "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/pkg/validation" "github.com/grafana/tempo/tempodb" "github.com/grafana/tempo/tempodb/backend" @@ -272,12 +271,12 @@ func (i *instance) CutCompleteTraces(cutoff time.Duration, immediate bool) error // CutBlockIfReady cuts a completingBlock from the HeadBlock if ready. // Returns the ID of a block if one was cut or a nil ID if one was not cut, along with the error (if any). -func (i *instance) CutBlockIfReady(maxBlockLifetime time.Duration, maxBlockBytes uint64, immediate bool) (google_uuid.UUID, error) { +func (i *instance) CutBlockIfReady(maxBlockLifetime time.Duration, maxBlockBytes uint64, immediate bool) (uuid.UUID, error) { i.headBlockMtx.Lock() defer i.headBlockMtx.Unlock() if i.headBlock == nil || i.headBlock.DataLength() == 0 { - return google_uuid.Nil, nil + return uuid.Nil, nil } now := time.Now() @@ -286,7 +285,7 @@ func (i *instance) CutBlockIfReady(maxBlockLifetime time.Duration, maxBlockBytes // Final flush err := i.headBlock.Flush() if err != nil { - return google_uuid.Nil, fmt.Errorf("failed to flush head block: %w", err) + return uuid.Nil, fmt.Errorf("failed to flush head block: %w", err) } completingBlock := i.headBlock @@ -304,21 +303,21 @@ func (i *instance) CutBlockIfReady(maxBlockLifetime time.Duration, maxBlockBytes err = i.resetHeadBlock() if err != nil { - return google_uuid.Nil, fmt.Errorf("failed to resetHeadBlock: %w", err) + return uuid.Nil, fmt.Errorf("failed to resetHeadBlock: %w", err) } - return completingBlock.BlockMeta().BlockID.UUID, nil + return (uuid.UUID)(completingBlock.BlockMeta().BlockID), nil } - return google_uuid.Nil, nil + return uuid.Nil, nil } // CompleteBlock moves a completingBlock to a completeBlock. The new completeBlock has the same ID. -func (i *instance) CompleteBlock(blockID google_uuid.UUID) error { +func (i *instance) CompleteBlock(blockID uuid.UUID) error { i.blocksMtx.Lock() var completingBlock common.WALBlock for _, iterBlock := range i.completingBlocks { - if iterBlock.BlockMeta().BlockID.UUID == blockID { + if (uuid.UUID)(iterBlock.BlockMeta().BlockID) == blockID { completingBlock = iterBlock break } @@ -345,13 +344,13 @@ func (i *instance) CompleteBlock(blockID google_uuid.UUID) error { return nil } -func (i *instance) ClearCompletingBlock(blockID google_uuid.UUID) error { +func (i *instance) ClearCompletingBlock(blockID uuid.UUID) error { i.blocksMtx.Lock() defer i.blocksMtx.Unlock() var completingBlock common.WALBlock for j, iterBlock := range i.completingBlocks { - if iterBlock.BlockMeta().BlockID.UUID == blockID { + if (uuid.UUID)(iterBlock.BlockMeta().BlockID) == blockID { completingBlock = iterBlock i.completingBlocks = append(i.completingBlocks[:j], i.completingBlocks[j+1:]...) break @@ -366,12 +365,12 @@ func (i *instance) ClearCompletingBlock(blockID google_uuid.UUID) error { } // GetBlockToBeFlushed gets a list of blocks that can be flushed to the backend. -func (i *instance) GetBlockToBeFlushed(blockID google_uuid.UUID) *LocalBlock { +func (i *instance) GetBlockToBeFlushed(blockID uuid.UUID) *LocalBlock { i.blocksMtx.RLock() defer i.blocksMtx.RUnlock() for _, c := range i.completeBlocks { - if c.BlockMeta().BlockID.UUID == blockID && c.FlushedTime().IsZero() { + if (uuid.UUID)(c.BlockMeta().BlockID) == blockID && c.FlushedTime().IsZero() { return c } } @@ -394,7 +393,7 @@ func (i *instance) ClearFlushedBlocks(completeBlockTimeout time.Duration) error if flushedTime.Add(completeBlockTimeout).Before(time.Now()) { i.completeBlocks = append(i.completeBlocks[:idx], i.completeBlocks[idx+1:]...) - err = i.local.ClearBlock(b.BlockMeta().BlockID.UUID, i.instanceID) + err = i.local.ClearBlock((uuid.UUID)(b.BlockMeta().BlockID), i.instanceID) if err == nil { metricBlocksClearedTotal.Inc() } @@ -518,7 +517,7 @@ func (i *instance) resetHeadBlock() error { dedicatedColumns := i.getDedicatedColumns() meta := &backend.BlockMeta{ - BlockID: uuid.New(), + BlockID: backend.NewUUID(), TenantID: i.instanceID, DedicatedColumns: dedicatedColumns, } @@ -586,11 +585,11 @@ func (i *instance) rediscoverLocalBlocks(ctx context.Context) ([]*LocalBlock, er return nil, err } - hasWal := func(id google_uuid.UUID) bool { + hasWal := func(id uuid.UUID) bool { i.blocksMtx.RLock() defer i.blocksMtx.RUnlock() for _, b := range i.completingBlocks { - if b.BlockMeta().BlockID.UUID == id { + if (uuid.UUID)(b.BlockMeta().BlockID) == id { return true } } diff --git a/modules/ingester/instance_search.go b/modules/ingester/instance_search.go index a34bc8c94f7..107d9cabaa9 100644 --- a/modules/ingester/instance_search.go +++ b/modules/ingester/instance_search.go @@ -119,7 +119,7 @@ func (i *instance) Search(ctx context.Context, req *tempopb.SearchRequest) (*tem i.headBlockMtx.RLock() span.AddEvent("acquired headblock mtx") if includeBlock(i.headBlock.BlockMeta(), req) { - search(i.headBlock.BlockMeta().BlockID.UUID, i.headBlock, "headBlock") + search((uuid.UUID)(i.headBlock.BlockMeta().BlockID), i.headBlock, "headBlock") } i.headBlockMtx.RUnlock() if err := anyErr.Load(); err != nil { @@ -150,7 +150,7 @@ func (i *instance) Search(ctx context.Context, req *tempopb.SearchRequest) (*tem wg.Add(1) go func(b common.WALBlock) { defer wg.Done() - search(b.BlockMeta().BlockID.UUID, b, "completingBlock") + search((uuid.UUID)(b.BlockMeta().BlockID), b, "completingBlock") }(b) } @@ -161,7 +161,7 @@ func (i *instance) Search(ctx context.Context, req *tempopb.SearchRequest) (*tem wg.Add(1) go func(b *LocalBlock) { defer wg.Done() - search(b.BlockMeta().BlockID.UUID, b, "completeBlock") + search((uuid.UUID)(b.BlockMeta().BlockID), b, "completeBlock") }(b) } diff --git a/modules/ingester/local_block.go b/modules/ingester/local_block.go index 75d9ade1a3e..62497865288 100644 --- a/modules/ingester/local_block.go +++ b/modules/ingester/local_block.go @@ -9,6 +9,7 @@ import ( "github.com/grafana/tempo/pkg/traceql" "go.uber.org/atomic" + "github.com/google/uuid" "github.com/grafana/tempo/pkg/tempopb" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/backend/local" @@ -41,7 +42,7 @@ func NewLocalBlock(ctx context.Context, existingBlock common.BackendBlock, l *lo writer: backend.NewWriter(l), } - flushedBytes, err := c.reader.Read(ctx, nameFlushed, c.BlockMeta().BlockID.UUID, c.BlockMeta().TenantID, nil) + flushedBytes, err := c.reader.Read(ctx, nameFlushed, (uuid.UUID)(c.BlockMeta().BlockID), c.BlockMeta().TenantID, nil) if err == nil { flushedTime := time.Time{} err = flushedTime.UnmarshalText(flushedBytes) @@ -107,7 +108,7 @@ func (c *LocalBlock) SetFlushed(ctx context.Context) error { return fmt.Errorf("error marshalling flush time to text: %w", err) } - err = c.writer.Write(ctx, nameFlushed, c.BlockMeta().BlockID.UUID, c.BlockMeta().TenantID, flushedBytes, nil) + err = c.writer.Write(ctx, nameFlushed, (uuid.UUID)(c.BlockMeta().BlockID), c.BlockMeta().TenantID, flushedBytes, nil) if err != nil { return fmt.Errorf("error writing ingester block flushed file: %w", err) } diff --git a/modules/querier/querier.go b/modules/querier/querier.go index a0ae76e0dfa..b5602462164 100644 --- a/modules/querier/querier.go +++ b/modules/querier/querier.go @@ -39,7 +39,6 @@ import ( "github.com/grafana/tempo/pkg/traceqlmetrics" "github.com/grafana/tempo/pkg/util" "github.com/grafana/tempo/pkg/util/log" - "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/pkg/validation" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/encoding/common" @@ -847,7 +846,7 @@ func (q *Querier) internalSearchBlock(ctx context.Context, req *tempopb.SearchBl return nil, fmt.Errorf("error extracting org id in Querier.BackendSearch: %w", err) } - blockID, err := uuid.Parse(req.BlockID) + blockID, err := backend.ParseUUID(req.BlockID) if err != nil { return nil, err } @@ -910,7 +909,7 @@ func (q *Querier) internalTagsSearchBlockV2(ctx context.Context, req *tempopb.Se return nil, fmt.Errorf("error extracting org id in Querier.BackendSearch: %w", err) } - blockID, err := uuid.Parse(req.BlockID) + blockID, err := backend.ParseUUID(req.BlockID) if err != nil { return nil, err } @@ -998,7 +997,7 @@ func (q *Querier) internalTagValuesSearchBlock(ctx context.Context, req *tempopb return &tempopb.SearchTagValuesResponse{}, fmt.Errorf("error extracting org id in Querier.BackendSearch: %w", err) } - blockID, err := uuid.Parse(req.BlockID) + blockID, err := backend.ParseUUID(req.BlockID) if err != nil { return &tempopb.SearchTagValuesResponse{}, err } @@ -1046,7 +1045,7 @@ func (q *Querier) internalTagValuesSearchBlockV2(ctx context.Context, req *tempo return &tempopb.SearchTagValuesV2Response{}, fmt.Errorf("error extracting org id in Querier.BackendSearch: %w", err) } - blockID, err := uuid.Parse(req.BlockID) + blockID, err := backend.ParseUUID(req.BlockID) if err != nil { return &tempopb.SearchTagValuesV2Response{}, err } diff --git a/modules/querier/querier_query_range.go b/modules/querier/querier_query_range.go index a95d00980e6..4239ed525ef 100644 --- a/modules/querier/querier_query_range.go +++ b/modules/querier/querier_query_range.go @@ -12,7 +12,6 @@ import ( v1 "github.com/grafana/tempo/pkg/tempopb/common/v1" "github.com/grafana/tempo/pkg/traceql" "github.com/grafana/tempo/pkg/util/log" - "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/encoding/common" ) @@ -62,7 +61,7 @@ func (q *Querier) queryBlock(ctx context.Context, req *tempopb.QueryRangeRequest return nil, fmt.Errorf("error extracting org id in Querier.queryBlock: %w", err) } - blockID, err := uuid.Parse(req.BlockID) + blockID, err := backend.ParseUUID(req.BlockID) if err != nil { return nil, err } From 7c9f76b6c4485b8f44ac34665a28516bd29c5c8e Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Mon, 23 Sep 2024 20:34:55 +0000 Subject: [PATCH 42/71] Re-plumb UUID through integration/ --- integration/poller/poller_test.go | 33 +++++++++++++++---------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/integration/poller/poller_test.go b/integration/poller/poller_test.go index a2e97655097..b8b83bbbbe2 100644 --- a/integration/poller/poller_test.go +++ b/integration/poller/poller_test.go @@ -12,7 +12,7 @@ import ( "time" "github.com/go-kit/log" - google_uuid "github.com/google/uuid" + "github.com/google/uuid" "github.com/grafana/e2e" "github.com/grafana/tempo/integration/util" "github.com/stretchr/testify/assert" @@ -22,7 +22,6 @@ import ( "github.com/grafana/tempo/cmd/tempo/app" e2eBackend "github.com/grafana/tempo/integration/e2e/backend" "github.com/grafana/tempo/pkg/blockboundary" - "github.com/grafana/tempo/pkg/uuid" "github.com/grafana/tempo/tempodb/backend" "github.com/grafana/tempo/tempodb/backend/azure" "github.com/grafana/tempo/tempodb/backend/gcs" @@ -162,7 +161,7 @@ func TestPollerOwnership(t *testing.T) { bb := blockboundary.CreateBlockBoundaries(listBlockConcurrency) tenantCount := 250 - tenantExpected := map[string][]google_uuid.UUID{} + tenantExpected := map[string][]uuid.UUID{} // Push some data to a few tenants for i := 0; i < tenantCount; i++ { @@ -189,9 +188,9 @@ func TestPollerOwnership(t *testing.T) { for testTenant, expected := range tenantExpected { metas := l.Metas(testTenant) - actual := []google_uuid.UUID{} + actual := []uuid.UUID{} for _, m := range metas { - actual = append(actual, m.BlockID.UUID) + actual = append(actual, (uuid.UUID)(m.BlockID)) } sort.Slice(actual, func(i, j int) bool { return actual[i].String() < actual[j].String() }) @@ -370,9 +369,9 @@ func TestTenantDeletion(t *testing.T) { } } -func found(id google_uuid.UUID, blockMetas []*backend.BlockMeta) bool { +func found(id uuid.UUID, blockMetas []*backend.BlockMeta) bool { for _, b := range blockMetas { - if b.BlockID.UUID == id { + if (uuid.UUID)(b.BlockID) == id { return true } } @@ -380,11 +379,11 @@ func found(id google_uuid.UUID, blockMetas []*backend.BlockMeta) bool { return false } -func writeTenantBlocks(t *testing.T, w backend.Writer, tenant string, blockIDs []google_uuid.UUID) { +func writeTenantBlocks(t *testing.T, w backend.Writer, tenant string, blockIDs []uuid.UUID) { var err error for _, b := range blockIDs { meta := &backend.BlockMeta{ - BlockID: uuid.From(b), + BlockID: backend.UUID(b), TenantID: tenant, } @@ -447,43 +446,43 @@ func writeBadBlockFiles(t *testing.T, ww backend.RawWriter, rr backend.RawReader t.Logf("items: %v", found) } -func pushBlocksToTenant(t *testing.T, tenant string, bb [][]byte, w backend.Writer) []google_uuid.UUID { +func pushBlocksToTenant(t *testing.T, tenant string, bb [][]byte, w backend.Writer) []uuid.UUID { // Randomly pick a block boundary r := mathrand.IntN(len(bb)) base := bb[r] t.Logf("base: %v", base) - expected := []google_uuid.UUID{} + expected := []uuid.UUID{} // Include the min and max in each tenant for testing - expected = append(expected, google_uuid.MustParse("00000000-0000-0000-0000-000000000000")) - expected = append(expected, google_uuid.MustParse("ffffffff-ffff-ffff-ffff-ffffffffffff")) + expected = append(expected, uuid.MustParse("00000000-0000-0000-0000-000000000000")) + expected = append(expected, uuid.MustParse("ffffffff-ffff-ffff-ffff-ffffffffffff")) // If we are above zero, then we have room to decrement if r > 0 { decrementUUIDBytes(base) - expected = append(expected, google_uuid.UUID(base)) + expected = append(expected, uuid.UUID(base)) } // If we are n-1 then we have room to increment if r < len(bb)-1 { // Grab the one after the boundary incrementUUIDBytes(base) - expected = append(expected, google_uuid.UUID(base)) + expected = append(expected, uuid.UUID(base)) } // If we are n-2 then we have room to increment again if r < len(bb)-2 { // Grab the one after the boundary incrementUUIDBytes(base) - expected = append(expected, google_uuid.UUID(base)) + expected = append(expected, uuid.UUID(base)) } // If we are n-3 then we have room to increment again if r < len(bb)-3 { // Grab the one after the boundary incrementUUIDBytes(base) - expected = append(expected, google_uuid.UUID(base)) + expected = append(expected, uuid.UUID(base)) } // Write the blocks using the expectaed block IDs From 06b223c35f331ed65743441ebe2d1a490e8da83e Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Mon, 23 Sep 2024 20:39:26 +0000 Subject: [PATCH 43/71] Drop package spec from tempo.proto --- pkg/tempopb/tempo.pb.go | 357 ++++++++++++++++++++-------------------- pkg/tempopb/tempo.proto | 2 - 2 files changed, 178 insertions(+), 181 deletions(-) diff --git a/pkg/tempopb/tempo.pb.go b/pkg/tempopb/tempo.pb.go index 5777c96ae80..065003baac0 100644 --- a/pkg/tempopb/tempo.pb.go +++ b/pkg/tempopb/tempo.pb.go @@ -3425,185 +3425,184 @@ func init() { func init() { proto.RegisterFile("pkg/tempopb/tempo.proto", fileDescriptor_f22805646f4f62b6) } var fileDescriptor_f22805646f4f62b6 = []byte{ - // 2837 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x3a, 0xcd, 0x6f, 0x1b, 0xc7, - 0xf5, 0x5a, 0xf1, 0xfb, 0x91, 0x94, 0xa8, 0xb1, 0xa2, 0xd0, 0xb4, 0x23, 0x2b, 0x1b, 0x23, 0x3f, - 0xfd, 0xf2, 0x41, 0xc9, 0x8c, 0x8d, 0xc4, 0x49, 0x9b, 0x42, 0xb2, 0x58, 0x47, 0x89, 0xbe, 0x32, - 0x64, 0x94, 0x20, 0x08, 0x20, 0xac, 0xc8, 0x31, 0xbd, 0x10, 0xb9, 0xcb, 0xec, 0x2e, 0x15, 0xab, - 0x87, 0x02, 0x2d, 0xd0, 0x43, 0x81, 0x1e, 0x7a, 0x68, 0x0f, 0x3d, 0xf6, 0x54, 0xf4, 0xd4, 0x43, - 0xfb, 0x1f, 0x14, 0x28, 0x02, 0x14, 0x0d, 0x02, 0xf4, 0x12, 0xf4, 0x10, 0x14, 0xc9, 0xa1, 0xfd, - 0x33, 0x8a, 0x79, 0x33, 0xb3, 0x3b, 0x4b, 0x2e, 0xa5, 0xb8, 0x51, 0xd0, 0x1c, 0x72, 0xe2, 0xcc, - 0x9b, 0x37, 0x6f, 0xde, 0xbc, 0xef, 0x37, 0x4b, 0x78, 0x72, 0x78, 0xd2, 0x5b, 0x0b, 0xd8, 0x60, - 0xe8, 0x0e, 0x8f, 0xc5, 0x6f, 0x7d, 0xe8, 0xb9, 0x81, 0x4b, 0x72, 0x12, 0x58, 0x5b, 0xea, 0xb8, - 0x83, 0x81, 0xeb, 0xac, 0x9d, 0xde, 0x5a, 0x13, 0x23, 0x81, 0x50, 0x7b, 0xb1, 0x67, 0x07, 0x0f, - 0x47, 0xc7, 0xf5, 0x8e, 0x3b, 0x58, 0xeb, 0xb9, 0x3d, 0x77, 0x0d, 0xc1, 0xc7, 0xa3, 0x07, 0x38, - 0xc3, 0x09, 0x8e, 0x24, 0xfa, 0x62, 0xe0, 0x59, 0x1d, 0xc6, 0xa9, 0xe0, 0x40, 0x40, 0xcd, 0x3f, - 0x19, 0x50, 0x69, 0xf3, 0xf9, 0xe6, 0xd9, 0xf6, 0x16, 0x65, 0x1f, 0x8e, 0x98, 0x1f, 0x90, 0x2a, - 0xe4, 0x10, 0x67, 0x7b, 0xab, 0x6a, 0xac, 0x18, 0xab, 0x25, 0xaa, 0xa6, 0x64, 0x19, 0xe0, 0xb8, - 0xef, 0x76, 0x4e, 0x5a, 0x81, 0xe5, 0x05, 0xd5, 0xd9, 0x15, 0x63, 0xb5, 0x40, 0x35, 0x08, 0xa9, - 0x41, 0x1e, 0x67, 0x4d, 0xa7, 0x5b, 0x4d, 0xe1, 0x6a, 0x38, 0x27, 0xd7, 0xa1, 0xf0, 0xe1, 0x88, - 0x79, 0x67, 0xbb, 0x6e, 0x97, 0x55, 0x33, 0xb8, 0x18, 0x01, 0xc8, 0x0b, 0xb0, 0x60, 0xf5, 0xfb, - 0xee, 0x47, 0x07, 0x96, 0x17, 0xd8, 0x56, 0x1f, 0x79, 0xaa, 0x66, 0x57, 0x8c, 0xd5, 0x3c, 0x9d, - 0x5c, 0x30, 0xff, 0x6d, 0xc0, 0x82, 0xc6, 0xb6, 0x3f, 0x74, 0x1d, 0x9f, 0x91, 0x9b, 0x90, 0x41, - 0x46, 0x91, 0xeb, 0x62, 0x63, 0xae, 0x2e, 0x45, 0x58, 0x47, 0x54, 0x2a, 0x16, 0xc9, 0x4b, 0x90, - 0x1b, 0xb0, 0xc0, 0xb3, 0x3b, 0x3e, 0x5e, 0xa0, 0xd8, 0xb8, 0x1a, 0xc7, 0xe3, 0x24, 0x77, 0x05, - 0x02, 0x55, 0x98, 0xe4, 0x2e, 0x64, 0xfd, 0xc0, 0x0a, 0x46, 0x3e, 0x5e, 0x6b, 0xae, 0xf1, 0xf4, - 0xe4, 0x1e, 0xc5, 0x46, 0xbd, 0x85, 0x88, 0x54, 0x6e, 0xe0, 0xd2, 0x1c, 0x30, 0xdf, 0xb7, 0x7a, - 0xac, 0x9a, 0xc6, 0x5b, 0xab, 0xa9, 0xf9, 0x0c, 0x64, 0x05, 0x2e, 0x29, 0x41, 0xfe, 0xde, 0xfe, - 0xee, 0xc1, 0x4e, 0xb3, 0xdd, 0xac, 0xcc, 0x90, 0x22, 0xe4, 0x0e, 0x36, 0x68, 0x7b, 0x7b, 0x63, - 0xa7, 0x62, 0x98, 0x44, 0x53, 0x90, 0x64, 0xcb, 0xfc, 0x64, 0x16, 0xca, 0x2d, 0x66, 0x79, 0x9d, - 0x87, 0x4a, 0x65, 0xaf, 0x42, 0xba, 0x6d, 0xf5, 0xfc, 0xaa, 0xb1, 0x92, 0x5a, 0x2d, 0x36, 0x56, - 0x42, 0xee, 0x62, 0x58, 0x75, 0x8e, 0xd2, 0x74, 0x02, 0xef, 0x6c, 0x33, 0xfd, 0xf1, 0xe7, 0x37, - 0x66, 0x28, 0xee, 0x21, 0x37, 0xa1, 0xbc, 0x6b, 0x3b, 0x5b, 0x23, 0xcf, 0x0a, 0x6c, 0xd7, 0xd9, - 0x15, 0x62, 0x29, 0xd3, 0x38, 0x10, 0xb1, 0xac, 0x47, 0x1a, 0x56, 0x4a, 0x62, 0xe9, 0x40, 0xb2, - 0x08, 0x99, 0x1d, 0x7b, 0x60, 0x07, 0x78, 0xd5, 0x32, 0x15, 0x13, 0x0e, 0xf5, 0xd1, 0x62, 0x32, - 0x02, 0x8a, 0x13, 0x52, 0x81, 0x14, 0x73, 0xba, 0xa8, 0xe4, 0x32, 0xe5, 0x43, 0x8e, 0xf7, 0x36, - 0xb7, 0x88, 0x6a, 0x1e, 0x05, 0x25, 0x26, 0x64, 0x15, 0xe6, 0x5b, 0x43, 0xcb, 0xf1, 0x0f, 0x98, - 0xc7, 0x7f, 0x5b, 0x2c, 0xa8, 0x16, 0x70, 0xcf, 0x38, 0xb8, 0xf6, 0x32, 0x14, 0xc2, 0x2b, 0x72, - 0xf2, 0x27, 0xec, 0x0c, 0x6d, 0xa1, 0x40, 0xf9, 0x90, 0x93, 0x3f, 0xb5, 0xfa, 0x23, 0x26, 0x0d, - 0x57, 0x4c, 0x5e, 0x9d, 0x7d, 0xc5, 0x30, 0xff, 0x92, 0x02, 0x22, 0x44, 0xb5, 0xc9, 0xcd, 0x55, - 0x49, 0xf5, 0x36, 0x14, 0x7c, 0x25, 0x40, 0x69, 0x54, 0x4b, 0xc9, 0xa2, 0xa5, 0x11, 0x22, 0x57, - 0x38, 0x1a, 0xfd, 0xf6, 0x96, 0x3c, 0x48, 0x4d, 0xb9, 0x0b, 0xe0, 0xd5, 0x0f, 0xb8, 0x31, 0x08, - 0xf9, 0x45, 0x00, 0x2e, 0xe1, 0xa1, 0xd5, 0x63, 0x7e, 0xdb, 0x15, 0xa4, 0xa5, 0x0c, 0xe3, 0x40, - 0xee, 0x62, 0xcc, 0xe9, 0xb8, 0x5d, 0xdb, 0xe9, 0x49, 0x2f, 0x0a, 0xe7, 0x9c, 0x82, 0xed, 0x74, - 0xd9, 0x23, 0x4e, 0xae, 0x65, 0xff, 0x88, 0x49, 0xd9, 0xc6, 0x81, 0xc4, 0x84, 0x52, 0xe0, 0x06, - 0x56, 0x9f, 0xb2, 0x8e, 0xeb, 0x75, 0xfd, 0x6a, 0x0e, 0x91, 0x62, 0x30, 0x8e, 0xd3, 0xb5, 0x02, - 0xab, 0xa9, 0x4e, 0x12, 0x0a, 0x89, 0xc1, 0xf8, 0x3d, 0x4f, 0x99, 0xe7, 0xdb, 0xae, 0x83, 0xfa, - 0x28, 0x50, 0x35, 0x25, 0x04, 0xd2, 0x3e, 0x3f, 0x1e, 0x56, 0x8c, 0xd5, 0x34, 0xc5, 0x31, 0x0f, - 0x1d, 0x0f, 0x5c, 0x37, 0x60, 0x1e, 0x32, 0x56, 0xc4, 0x33, 0x35, 0x08, 0xd9, 0x82, 0x4a, 0x97, - 0x75, 0xed, 0x8e, 0x15, 0xb0, 0xee, 0x3d, 0xb7, 0x3f, 0x1a, 0x38, 0x7e, 0xb5, 0x84, 0xd6, 0x5c, - 0x0d, 0x45, 0xbe, 0x15, 0x47, 0xa0, 0x13, 0x3b, 0xcc, 0x3f, 0x1b, 0x30, 0x3f, 0x86, 0x45, 0x6e, - 0x43, 0xc6, 0xef, 0xb8, 0x43, 0x26, 0x5d, 0x77, 0x79, 0x1a, 0xb9, 0x7a, 0x8b, 0x63, 0x51, 0x81, - 0xcc, 0xef, 0xe0, 0x58, 0x03, 0x65, 0x2b, 0x38, 0x26, 0xb7, 0x20, 0x1d, 0x9c, 0x0d, 0x45, 0x7c, - 0x99, 0x6b, 0x3c, 0x35, 0x95, 0x50, 0xfb, 0x6c, 0xc8, 0x28, 0xa2, 0x9a, 0x37, 0x20, 0x83, 0x64, - 0x49, 0x1e, 0xd2, 0xad, 0x83, 0x8d, 0xbd, 0xca, 0x0c, 0x77, 0x76, 0xda, 0x6c, 0xed, 0xbf, 0x43, - 0xef, 0x35, 0xd1, 0xbf, 0xd3, 0x1c, 0x9d, 0x00, 0x64, 0x5b, 0x6d, 0xba, 0xbd, 0x77, 0xbf, 0x32, - 0x63, 0x3e, 0x82, 0x39, 0x65, 0x5d, 0x32, 0xb4, 0xdd, 0x86, 0x2c, 0x46, 0x2f, 0xe5, 0xe1, 0xd7, - 0xe3, 0xf1, 0x47, 0x60, 0xef, 0xb2, 0xc0, 0xe2, 0x1a, 0xa2, 0x12, 0x97, 0xac, 0x8f, 0x87, 0xba, - 0x71, 0xeb, 0x1d, 0x8f, 0x73, 0xe6, 0xdf, 0x53, 0x70, 0x25, 0x81, 0xe2, 0x78, 0x4a, 0x28, 0x44, - 0x29, 0x61, 0x15, 0xe6, 0x3d, 0xd7, 0x0d, 0x5a, 0xcc, 0x3b, 0xb5, 0x3b, 0x6c, 0x2f, 0x12, 0xd9, - 0x38, 0x98, 0x5b, 0x27, 0x07, 0x21, 0x79, 0xc4, 0x13, 0x19, 0x22, 0x0e, 0xe4, 0x89, 0x00, 0x5d, - 0xa2, 0x6d, 0x0f, 0xd8, 0x3b, 0x8e, 0xfd, 0x68, 0xcf, 0x72, 0x5c, 0xf4, 0x84, 0x34, 0x9d, 0x5c, - 0xe0, 0x56, 0xd5, 0x8d, 0x42, 0x92, 0x08, 0x2f, 0x1a, 0x84, 0x3c, 0x07, 0x39, 0x5f, 0xc6, 0x8c, - 0x2c, 0x4a, 0xa0, 0x12, 0x49, 0x40, 0xc0, 0xa9, 0x42, 0x20, 0x2f, 0x40, 0x5e, 0x0e, 0xb9, 0x4f, - 0xa4, 0x12, 0x91, 0x43, 0x0c, 0x42, 0xa1, 0xe4, 0x8b, 0xcb, 0xf1, 0x18, 0xee, 0x57, 0xf3, 0xb8, - 0xa3, 0x7e, 0x9e, 0x5e, 0xea, 0x2d, 0x6d, 0x03, 0x06, 0x29, 0x1a, 0xa3, 0x51, 0x3b, 0x84, 0x85, - 0x09, 0x94, 0x84, 0x38, 0xf6, 0xbc, 0x1e, 0xc7, 0x8a, 0x8d, 0x27, 0x34, 0xa5, 0x46, 0x9b, 0xf5, - 0xf0, 0xb6, 0x03, 0x25, 0x7d, 0x09, 0xe3, 0xd0, 0xd0, 0x72, 0xee, 0xb9, 0x23, 0x27, 0x40, 0xc2, - 0x3c, 0x0e, 0x29, 0x00, 0x97, 0x29, 0xf3, 0x3c, 0xd7, 0x13, 0xcb, 0x22, 0x19, 0x68, 0x10, 0xf3, - 0x67, 0x06, 0xe4, 0xa4, 0x3c, 0xc8, 0x33, 0x90, 0xe1, 0x1b, 0x95, 0x59, 0x96, 0x63, 0x02, 0xa3, - 0x62, 0x0d, 0x33, 0xa0, 0x15, 0x74, 0x1e, 0xb2, 0xae, 0xa4, 0xa6, 0xa6, 0xe4, 0x35, 0x00, 0x2b, - 0x08, 0x3c, 0xfb, 0x78, 0x14, 0x30, 0x9e, 0x51, 0x38, 0x8d, 0x6b, 0x21, 0x0d, 0x59, 0xee, 0x9c, - 0xde, 0xaa, 0xbf, 0xc5, 0xce, 0x0e, 0xf9, 0x6d, 0xa8, 0x86, 0xce, 0x7d, 0x3d, 0xcd, 0x8f, 0x21, - 0x4b, 0x90, 0xe5, 0x07, 0x85, 0xb6, 0x29, 0x67, 0x89, 0x2e, 0x9c, 0x68, 0x5e, 0xa9, 0x69, 0xe6, - 0x75, 0x13, 0xca, 0xca, 0x98, 0xf8, 0xdc, 0x97, 0x86, 0x18, 0x07, 0x8e, 0xdd, 0x22, 0xf3, 0x78, - 0xb7, 0xf8, 0x4d, 0x98, 0xcb, 0xa5, 0x33, 0x72, 0x8f, 0xb2, 0x1d, 0x7f, 0xc8, 0x3a, 0x01, 0xeb, - 0xb6, 0x95, 0xd3, 0x63, 0xbe, 0x1b, 0x03, 0x93, 0x67, 0x61, 0x2e, 0x04, 0x6d, 0x9e, 0xf1, 0xc3, - 0x67, 0x91, 0xbf, 0x31, 0x28, 0x59, 0x81, 0x22, 0x46, 0x77, 0x4c, 0x6e, 0x2a, 0x73, 0xeb, 0x20, - 0x7e, 0xd1, 0x8e, 0x3b, 0x18, 0xf6, 0x59, 0xc0, 0xba, 0x6f, 0xba, 0xc7, 0xbe, 0xca, 0x3d, 0x31, - 0x20, 0xb7, 0x1b, 0xdc, 0x84, 0x18, 0xc2, 0xd9, 0x22, 0x00, 0xe7, 0x3b, 0x22, 0x29, 0xd8, 0xc9, - 0x22, 0x3b, 0xe3, 0xe0, 0x18, 0xdf, 0x98, 0xc3, 0x31, 0x07, 0xe9, 0x7c, 0x23, 0xd4, 0xec, 0x71, - 0x7f, 0xe0, 0xa2, 0xe1, 0x59, 0x5d, 0x25, 0xe5, 0x45, 0x15, 0xce, 0x85, 0xb2, 0x65, 0xb8, 0x5e, - 0x84, 0x0c, 0x16, 0x93, 0x2a, 0xb7, 0xe3, 0x24, 0x2a, 0x3c, 0x52, 0x09, 0x85, 0x47, 0x3a, 0x2c, - 0x3c, 0xcc, 0x4f, 0x52, 0xb0, 0x14, 0x9d, 0x14, 0xab, 0x01, 0x5e, 0x99, 0xac, 0x01, 0x6a, 0x63, - 0x51, 0x54, 0xe3, 0xee, 0xbb, 0x3a, 0xe0, 0xdb, 0x51, 0x07, 0x7c, 0x96, 0x82, 0x6b, 0xa1, 0x72, - 0xd0, 0xe9, 0xe2, 0x5a, 0xfd, 0xfe, 0xa4, 0x56, 0x6f, 0x4c, 0x6a, 0x55, 0x6c, 0xfc, 0x4e, 0xb5, - 0xdf, 0x2a, 0xd5, 0xae, 0xab, 0x52, 0x5d, 0xb8, 0x9d, 0x2c, 0x90, 0x6a, 0x90, 0x0f, 0xac, 0x1e, - 0xaf, 0x20, 0x44, 0x2e, 0x2a, 0xd0, 0x70, 0x6e, 0xbe, 0x09, 0x8b, 0xd1, 0x8e, 0xc3, 0x46, 0xb8, - 0xa7, 0x01, 0x59, 0x0c, 0x1e, 0x2a, 0x7b, 0x25, 0xf9, 0xf5, 0x61, 0x43, 0x54, 0x85, 0x12, 0xd3, - 0x7c, 0x4d, 0x0f, 0x49, 0x72, 0x31, 0x4c, 0x34, 0x86, 0x96, 0x68, 0x08, 0xa4, 0x03, 0xde, 0x91, - 0xcd, 0x22, 0x33, 0x38, 0x36, 0x87, 0x5a, 0x94, 0x89, 0xd9, 0x16, 0xd6, 0x57, 0x82, 0xdd, 0xb0, - 0xbe, 0x12, 0xd3, 0x8b, 0x02, 0x5b, 0x3a, 0x21, 0xb0, 0x65, 0xa2, 0xc0, 0xf6, 0x32, 0x3c, 0x39, - 0x71, 0xa2, 0xbc, 0x3d, 0x0f, 0xe6, 0x0a, 0x28, 0x45, 0x16, 0x01, 0xcc, 0xdb, 0x90, 0x57, 0x5b, - 0xf0, 0x2a, 0x67, 0x61, 0xc0, 0xc5, 0x71, 0x72, 0x2f, 0x65, 0xee, 0xc0, 0xd5, 0xb1, 0xe3, 0x34, - 0x71, 0xaf, 0x8d, 0x1f, 0x58, 0x6c, 0x2c, 0x44, 0xe5, 0x92, 0x5c, 0xd1, 0x79, 0xd8, 0x83, 0x0c, - 0x26, 0x3a, 0xd2, 0x84, 0xb2, 0xc7, 0x7c, 0x77, 0xe4, 0x75, 0x58, 0x4b, 0xab, 0x36, 0x22, 0x8f, - 0x15, 0x4f, 0x1a, 0xa7, 0xb7, 0xea, 0x54, 0x47, 0xa3, 0xf1, 0x5d, 0xe6, 0x1e, 0x94, 0x0e, 0x46, - 0x7e, 0x54, 0x54, 0xbf, 0x0e, 0x65, 0x2c, 0x6b, 0xfc, 0xcd, 0xb3, 0xb6, 0x7c, 0x37, 0x48, 0xad, - 0xce, 0x69, 0xc6, 0xc8, 0xb1, 0x9b, 0x1c, 0x83, 0x32, 0xcb, 0x77, 0x1d, 0x1a, 0x47, 0x37, 0x7f, - 0x6b, 0x40, 0x85, 0xa3, 0x60, 0x52, 0x53, 0x9a, 0x7c, 0x31, 0xac, 0xd4, 0xb9, 0xe6, 0x4b, 0x9b, - 0x4f, 0xf0, 0x4e, 0xfb, 0x1f, 0x9f, 0xdf, 0x28, 0x1f, 0x78, 0xcc, 0xea, 0xf7, 0xdd, 0x8e, 0xc0, - 0x56, 0x25, 0xfa, 0xff, 0x41, 0xca, 0xee, 0x8a, 0xd2, 0x67, 0x2a, 0x2e, 0xc7, 0x20, 0x77, 0x00, - 0x44, 0xfc, 0xd9, 0xb2, 0x02, 0xab, 0x9a, 0x3e, 0x0f, 0x5f, 0x43, 0x34, 0x77, 0x05, 0x8b, 0x42, - 0x1e, 0x92, 0xc5, 0xbb, 0x90, 0x3b, 0xc6, 0x02, 0xec, 0x2b, 0x0b, 0x52, 0xe1, 0x9b, 0x37, 0x01, - 0xe4, 0x6b, 0x04, 0xcf, 0xe3, 0x4b, 0xb1, 0xae, 0xa4, 0xa4, 0x2e, 0x65, 0xbe, 0x0e, 0x85, 0x1d, - 0xdb, 0x39, 0x69, 0xf5, 0xed, 0x0e, 0x6f, 0x9a, 0x32, 0x7d, 0xdb, 0x39, 0x51, 0x67, 0x5d, 0x9b, - 0x3c, 0x8b, 0x9f, 0x51, 0xe7, 0x1b, 0xa8, 0xc0, 0x34, 0x7f, 0x6a, 0x00, 0xe1, 0x40, 0xd5, 0x9e, - 0x44, 0x99, 0x5f, 0xb8, 0x82, 0xa1, 0xbb, 0x42, 0x15, 0x72, 0x3d, 0xcf, 0x1d, 0x0d, 0x37, 0x95, - 0x8b, 0xa8, 0x29, 0xc7, 0xef, 0xe3, 0x63, 0x84, 0xa8, 0xef, 0xc4, 0xe4, 0x2b, 0xbb, 0xce, 0xcf, - 0x0d, 0xb8, 0xaa, 0x31, 0xd1, 0x1a, 0x0d, 0x06, 0x96, 0x77, 0xf6, 0xbf, 0xe1, 0xe5, 0xf7, 0x06, - 0x5c, 0x89, 0x09, 0x24, 0xf2, 0x61, 0xe6, 0x07, 0xf6, 0x80, 0xc7, 0x47, 0xe4, 0x24, 0x4f, 0x23, - 0x40, 0xbc, 0xcc, 0x17, 0x95, 0xa1, 0x56, 0xe6, 0x3f, 0x0b, 0x73, 0x68, 0xce, 0xad, 0x10, 0x45, - 0xb0, 0x36, 0x06, 0x25, 0xf5, 0xa8, 0x89, 0x4c, 0xa3, 0x06, 0x17, 0x63, 0x45, 0xfe, 0x44, 0x0b, - 0xf9, 0x3d, 0x28, 0x51, 0xeb, 0xa3, 0x37, 0x6c, 0x3f, 0x70, 0x7b, 0x9e, 0x35, 0xe0, 0x46, 0x72, - 0x3c, 0xea, 0x9c, 0x30, 0xd1, 0x69, 0xa4, 0xa9, 0x9c, 0xf1, 0xbb, 0x77, 0x34, 0xce, 0xc4, 0xc4, - 0x7c, 0x13, 0xf2, 0xaa, 0x4c, 0x4e, 0xe8, 0x7c, 0x5e, 0x88, 0x77, 0x3e, 0x4b, 0xf1, 0x6e, 0xeb, - 0xed, 0x1d, 0xde, 0xde, 0xd8, 0x1d, 0x15, 0x8d, 0x7e, 0x65, 0x40, 0x51, 0x63, 0x91, 0x6c, 0xc2, - 0x42, 0xdf, 0x0a, 0x98, 0xd3, 0x39, 0x3b, 0x7a, 0xa8, 0xd8, 0x93, 0x56, 0x19, 0xf5, 0x50, 0x3a, - 0xef, 0xb4, 0x22, 0xf1, 0xa3, 0xdb, 0xfc, 0x3f, 0x64, 0x7d, 0xe6, 0xd9, 0xd2, 0xbd, 0xf5, 0x08, - 0x16, 0x56, 0xf7, 0x12, 0x81, 0x5f, 0x5c, 0xc4, 0x0b, 0x29, 0x58, 0x39, 0x33, 0xff, 0x16, 0xb7, - 0x6e, 0x69, 0x58, 0x93, 0x4d, 0xd9, 0x05, 0xda, 0x9a, 0x4d, 0xd4, 0x56, 0xc4, 0x5f, 0xea, 0x22, - 0xfe, 0x2a, 0x90, 0x1a, 0xde, 0xbd, 0x2b, 0x5b, 0x1a, 0x3e, 0x14, 0x90, 0x3b, 0x68, 0x78, 0x08, - 0xb9, 0x23, 0x20, 0xeb, 0xb2, 0x8e, 0xe7, 0x43, 0x84, 0xdc, 0x59, 0x97, 0x05, 0x3b, 0x1f, 0x9a, - 0xef, 0x42, 0x2d, 0xc9, 0x4f, 0xa4, 0x89, 0xde, 0x85, 0x82, 0x8f, 0x20, 0x9b, 0x4d, 0x86, 0x80, - 0x84, 0x7d, 0x11, 0xb6, 0xf9, 0x6b, 0x03, 0xca, 0x31, 0xc5, 0xc6, 0x32, 0x51, 0x46, 0x66, 0xa2, - 0x12, 0x18, 0x0e, 0x0a, 0x23, 0x45, 0x0d, 0x87, 0xcf, 0x1e, 0xa0, 0xbc, 0x0d, 0x6a, 0x3c, 0xe0, - 0x33, 0x5f, 0xbe, 0xba, 0x1a, 0x3e, 0x9f, 0x1d, 0xe3, 0xe5, 0xf2, 0xd4, 0x38, 0xe6, 0xb3, 0xae, - 0xbc, 0x98, 0xd1, 0xc5, 0x1e, 0x52, 0x3c, 0xf0, 0xe6, 0x90, 0xb6, 0x7a, 0xbd, 0x25, 0x90, 0x3e, - 0xb1, 0x9d, 0x2e, 0x56, 0x47, 0x19, 0x8a, 0x63, 0x93, 0x89, 0x07, 0x49, 0xc9, 0x38, 0x0f, 0xb3, - 0xbc, 0xf4, 0xf1, 0x98, 0x3f, 0xea, 0x07, 0xed, 0x28, 0x51, 0x6a, 0x10, 0x5e, 0x6a, 0x88, 0x99, - 0x34, 0x9b, 0x5a, 0xa2, 0x0f, 0x21, 0x06, 0x95, 0x98, 0x3c, 0x0a, 0x2e, 0x4c, 0xac, 0x72, 0x33, - 0xe9, 0x5b, 0xc7, 0xac, 0xaf, 0xd5, 0x0a, 0x11, 0x80, 0xf3, 0x81, 0x93, 0x43, 0x2d, 0x37, 0x6b, - 0x10, 0xb2, 0x06, 0xb3, 0x81, 0x32, 0x8d, 0x1b, 0xd3, 0x79, 0x38, 0x70, 0x6d, 0x27, 0xa0, 0xb3, - 0x81, 0xcf, 0x7d, 0x68, 0x29, 0x79, 0x19, 0x95, 0x61, 0x4b, 0x26, 0xca, 0x14, 0xc7, 0xdc, 0x3a, - 0x4e, 0xad, 0x3e, 0x1e, 0x6c, 0x50, 0x3e, 0xe4, 0x5d, 0x21, 0x7b, 0xc4, 0x06, 0xc3, 0xbe, 0xe5, - 0xb5, 0xe5, 0x0b, 0x52, 0x0a, 0x3f, 0x2a, 0x8c, 0x83, 0xc9, 0x73, 0x50, 0x51, 0x20, 0xf5, 0xa2, - 0x2c, 0x8d, 0x73, 0x02, 0x6e, 0xb6, 0xe0, 0x0a, 0x3e, 0x0e, 0x6f, 0x3b, 0x7e, 0x60, 0x39, 0xc1, - 0xf9, 0x51, 0x39, 0x8c, 0xb2, 0x32, 0xd2, 0xc4, 0xa2, 0xac, 0xf0, 0x4d, 0x8c, 0xb2, 0x8f, 0x60, - 0x31, 0x4e, 0x54, 0x9a, 0x70, 0x3d, 0xf4, 0x29, 0x61, 0xbf, 0x51, 0xd8, 0x91, 0x98, 0x2d, 0x5c, - 0x0d, 0x1d, 0xeb, 0xf1, 0x9f, 0xdd, 0x7e, 0x62, 0x40, 0x39, 0x46, 0x8b, 0xdc, 0x85, 0x2c, 0xaa, - 0x6d, 0xd2, 0x67, 0x26, 0xdf, 0x13, 0xe4, 0x6b, 0xbe, 0xdc, 0x10, 0x2f, 0xcd, 0x0c, 0x19, 0x0c, - 0xc9, 0x0d, 0x28, 0x0e, 0x3d, 0x77, 0x70, 0x24, 0xa9, 0x8a, 0xb7, 0x37, 0xe0, 0xa0, 0x1d, 0x84, - 0x98, 0x7f, 0x48, 0xc1, 0x02, 0x5e, 0x9f, 0x5a, 0x4e, 0x8f, 0x5d, 0x8a, 0x44, 0xb1, 0x4b, 0x08, - 0xd8, 0x50, 0xaa, 0x11, 0xc7, 0xf1, 0xef, 0x40, 0xb9, 0xf1, 0xef, 0x40, 0x5a, 0x67, 0x95, 0x3f, - 0xa7, 0xb3, 0x2a, 0x5c, 0xd8, 0x59, 0x41, 0x52, 0x67, 0xa5, 0xf5, 0x33, 0xc5, 0x78, 0x3f, 0xa3, - 0xf7, 0x5c, 0xa5, 0xb1, 0x9e, 0x4b, 0xf5, 0x3a, 0xe5, 0xa9, 0xbd, 0xce, 0xdc, 0x57, 0xea, 0x75, - 0xe6, 0x1f, 0xb7, 0xd7, 0xc1, 0xfc, 0x2e, 0x4d, 0xdf, 0xaf, 0x56, 0xc4, 0x9d, 0x43, 0x80, 0xe9, - 0x03, 0xd1, 0x15, 0x26, 0xad, 0xf5, 0xf9, 0x31, 0x6b, 0xbd, 0x12, 0x25, 0x49, 0x7b, 0xc0, 0xbe, - 0xb6, 0xa9, 0xfe, 0x18, 0xf2, 0x4d, 0xc9, 0xc1, 0xe5, 0x1b, 0xe9, 0xd3, 0x50, 0xe2, 0x61, 0xc4, - 0x0f, 0xac, 0xc1, 0xf0, 0x68, 0x20, 0xac, 0x34, 0x45, 0x8b, 0x21, 0x6c, 0xd7, 0x37, 0x37, 0x20, - 0xdb, 0xb2, 0x06, 0xc3, 0xfe, 0x24, 0xf2, 0xec, 0x04, 0x72, 0x74, 0x8a, 0xa1, 0x9d, 0x62, 0x7e, - 0x6a, 0x00, 0x44, 0xb2, 0xf8, 0x3a, 0xb7, 0x58, 0x83, 0x9c, 0x8f, 0xcc, 0xa8, 0x72, 0x60, 0x3e, - 0x12, 0x1f, 0xc2, 0x25, 0xbe, 0xc2, 0xba, 0xd0, 0x0b, 0xc9, 0x1d, 0x5d, 0xe3, 0xe9, 0xb1, 0x14, - 0xae, 0x04, 0x2f, 0xa9, 0x46, 0x98, 0xcf, 0x7d, 0x00, 0xf3, 0x63, 0xcd, 0x0a, 0x29, 0x41, 0x7e, - 0x6f, 0xff, 0xa8, 0x49, 0xe9, 0x3e, 0xad, 0xcc, 0x90, 0x2b, 0x30, 0xbf, 0xbb, 0xf1, 0xde, 0xd1, - 0xce, 0xf6, 0x61, 0xf3, 0xa8, 0x4d, 0x37, 0xee, 0x35, 0x5b, 0x15, 0x83, 0x03, 0x71, 0x7c, 0xd4, - 0xde, 0xdf, 0x3f, 0xda, 0xd9, 0xa0, 0xf7, 0x9b, 0x95, 0x59, 0xb2, 0x00, 0xe5, 0x77, 0xf6, 0xde, - 0xda, 0xdb, 0x7f, 0x77, 0x4f, 0x6e, 0x4e, 0x35, 0x7e, 0x61, 0x40, 0x96, 0x93, 0x67, 0x1e, 0xf9, - 0x01, 0x14, 0xc2, 0x96, 0x87, 0x5c, 0x8d, 0x75, 0x4a, 0x7a, 0x1b, 0x54, 0x7b, 0x22, 0xb6, 0xa4, - 0x8c, 0xd3, 0x9c, 0x21, 0x1b, 0x50, 0x0c, 0x91, 0x0f, 0x1b, 0xff, 0x0d, 0x89, 0xc6, 0xbf, 0x0c, - 0xa8, 0x48, 0xbb, 0xbc, 0xcf, 0x1c, 0xe6, 0x59, 0x81, 0x1b, 0x32, 0x86, 0xfd, 0xca, 0x18, 0x55, - 0xbd, 0xf9, 0x99, 0xce, 0xd8, 0x36, 0xc0, 0x7d, 0x16, 0xa8, 0x5a, 0xf1, 0x5a, 0x72, 0x72, 0x14, - 0x34, 0xae, 0x4f, 0xc9, 0x9c, 0x8a, 0xd4, 0x7d, 0x80, 0xc8, 0x31, 0x49, 0x94, 0xeb, 0x27, 0xc2, - 0x6b, 0xed, 0x5a, 0xe2, 0x5a, 0x78, 0xd3, 0xdf, 0xa5, 0x21, 0xc7, 0x17, 0x6c, 0xe6, 0x91, 0x37, - 0xa0, 0xfc, 0x43, 0xdb, 0xe9, 0x86, 0x1f, 0x83, 0xc9, 0xd5, 0xa4, 0x6f, 0xd0, 0x82, 0x6c, 0x6d, - 0xfa, 0xe7, 0x69, 0x54, 0x41, 0x49, 0x7d, 0x5e, 0xea, 0x30, 0x27, 0x20, 0x53, 0xbe, 0x69, 0xd6, - 0x9e, 0x9c, 0x80, 0x87, 0x24, 0x9a, 0x50, 0xd4, 0xbe, 0x97, 0xea, 0xd2, 0x9a, 0xf8, 0x8a, 0x7a, - 0x1e, 0x99, 0xfb, 0x00, 0xd1, 0x6b, 0x0a, 0x39, 0xe7, 0x5d, 0xb5, 0x76, 0x2d, 0x71, 0x2d, 0x24, - 0xf4, 0x96, 0xba, 0x92, 0x78, 0x96, 0x39, 0x97, 0xd4, 0x53, 0x89, 0xcf, 0x3c, 0x1a, 0xb1, 0x43, - 0x98, 0x1f, 0x7b, 0xc5, 0x20, 0x17, 0x3d, 0x0e, 0xd6, 0x56, 0xa6, 0x23, 0x84, 0x74, 0xdf, 0xd7, - 0xde, 0x8e, 0xd4, 0xeb, 0xc8, 0xc5, 0x94, 0xcd, 0x69, 0x08, 0x3a, 0xcf, 0x8d, 0xbf, 0xa6, 0xa1, - 0xd2, 0x0a, 0x3c, 0x66, 0x0d, 0x6c, 0xa7, 0xa7, 0x4c, 0xe6, 0x35, 0xc8, 0xca, 0xc4, 0xf7, 0xb8, - 0x2a, 0x5e, 0x37, 0xb8, 0x3f, 0x5c, 0x8a, 0x6e, 0xd6, 0x0d, 0xb2, 0x7b, 0x89, 0xda, 0x59, 0x37, - 0xc8, 0x7b, 0xdf, 0x8c, 0x7e, 0xd6, 0x0d, 0xf2, 0xc1, 0x37, 0xa7, 0xa1, 0x75, 0x83, 0x1c, 0xc0, - 0x82, 0x8c, 0x15, 0x97, 0x12, 0x1d, 0xd6, 0x0d, 0x72, 0x08, 0x57, 0x74, 0x8a, 0xb2, 0x84, 0x24, - 0xd7, 0xe3, 0xfb, 0xe2, 0x45, 0xb2, 0x26, 0xe1, 0xa4, 0x6a, 0x97, 0xd3, 0x6d, 0xfc, 0xd1, 0x80, - 0x9c, 0x8a, 0x84, 0x47, 0x89, 0xdd, 0xaa, 0x79, 0x5e, 0x0f, 0x27, 0x0f, 0x7a, 0xe6, 0x5c, 0x9c, - 0x4b, 0x8f, 0x96, 0x9b, 0xaf, 0x7f, 0xfc, 0xc5, 0xb2, 0xf1, 0xe9, 0x17, 0xcb, 0xc6, 0x3f, 0xbf, - 0x58, 0x36, 0x7e, 0xf9, 0xe5, 0xf2, 0xcc, 0xa7, 0x5f, 0x2e, 0xcf, 0x7c, 0xf6, 0xe5, 0xf2, 0xcc, - 0xfb, 0x37, 0xf5, 0xff, 0x4a, 0x79, 0xd6, 0x03, 0xcb, 0xb1, 0xc4, 0x9f, 0xad, 0xd6, 0xb4, 0xbf, - 0x5f, 0x1d, 0x67, 0xf1, 0x3f, 0x51, 0x2f, 0xfd, 0x27, 0x00, 0x00, 0xff, 0xff, 0x58, 0x5b, 0x43, - 0x93, 0x94, 0x25, 0x00, 0x00, + // 2818 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x1a, 0x4d, 0x6f, 0x1b, 0xc7, + 0x55, 0x2b, 0x7e, 0x3f, 0x92, 0x12, 0x35, 0x56, 0x14, 0x9a, 0x76, 0x64, 0x65, 0x63, 0xa4, 0x6a, + 0x3e, 0x28, 0x99, 0xb1, 0x91, 0x38, 0x69, 0x53, 0x48, 0x16, 0xeb, 0x28, 0xd1, 0x57, 0x86, 0x8c, + 0x12, 0x14, 0x01, 0x84, 0x15, 0x39, 0xa6, 0x17, 0x22, 0x77, 0x99, 0xdd, 0xa5, 0x62, 0xf5, 0x50, + 0xa0, 0x05, 0x7a, 0x28, 0xd0, 0x43, 0x0f, 0xed, 0xa1, 0xc7, 0x9e, 0x8a, 0x9e, 0x7a, 0x68, 0xff, + 0x41, 0x81, 0x22, 0x40, 0xd1, 0x20, 0x40, 0x2f, 0x41, 0x0f, 0x41, 0x91, 0x1c, 0xda, 0x9f, 0x51, + 0xcc, 0x9b, 0x99, 0xdd, 0x59, 0x72, 0x29, 0xc5, 0x8d, 0x82, 0xe6, 0x90, 0x93, 0xe6, 0xbd, 0x7d, + 0xf3, 0xe6, 0xcd, 0xfb, 0x7e, 0x43, 0xc1, 0x93, 0xc3, 0x93, 0xde, 0x5a, 0xc0, 0x06, 0x43, 0x77, + 0x78, 0x2c, 0xfe, 0xd6, 0x87, 0x9e, 0x1b, 0xb8, 0x24, 0x27, 0x91, 0xb5, 0xa5, 0x8e, 0x3b, 0x18, + 0xb8, 0xce, 0xda, 0xe9, 0xad, 0x35, 0xb1, 0x12, 0x04, 0xb5, 0x17, 0x7b, 0x76, 0xf0, 0x70, 0x74, + 0x5c, 0xef, 0xb8, 0x83, 0xb5, 0x9e, 0xdb, 0x73, 0xd7, 0x10, 0x7d, 0x3c, 0x7a, 0x80, 0x10, 0x02, + 0xb8, 0x92, 0xe4, 0x8b, 0x81, 0x67, 0x75, 0x18, 0xe7, 0x82, 0x0b, 0x81, 0x35, 0xff, 0x6c, 0x40, + 0xa5, 0xcd, 0xe1, 0xcd, 0xb3, 0xed, 0x2d, 0xca, 0x3e, 0x18, 0x31, 0x3f, 0x20, 0x55, 0xc8, 0x21, + 0xcd, 0xf6, 0x56, 0xd5, 0x58, 0x31, 0x56, 0x4b, 0x54, 0x81, 0x64, 0x19, 0xe0, 0xb8, 0xef, 0x76, + 0x4e, 0x5a, 0x81, 0xe5, 0x05, 0xd5, 0xd9, 0x15, 0x63, 0xb5, 0x40, 0x35, 0x0c, 0xa9, 0x41, 0x1e, + 0xa1, 0xa6, 0xd3, 0xad, 0xa6, 0xf0, 0x6b, 0x08, 0x93, 0xeb, 0x50, 0xf8, 0x60, 0xc4, 0xbc, 0xb3, + 0x5d, 0xb7, 0xcb, 0xaa, 0x19, 0xfc, 0x18, 0x21, 0xc8, 0x0b, 0xb0, 0x60, 0xf5, 0xfb, 0xee, 0x87, + 0x07, 0x96, 0x17, 0xd8, 0x56, 0x1f, 0x65, 0xaa, 0x66, 0x57, 0x8c, 0xd5, 0x3c, 0x9d, 0xfc, 0x60, + 0xfe, 0xc7, 0x80, 0x05, 0x4d, 0x6c, 0x7f, 0xe8, 0x3a, 0x3e, 0x23, 0x37, 0x21, 0x83, 0x82, 0xa2, + 0xd4, 0xc5, 0xc6, 0x5c, 0x5d, 0xaa, 0xb0, 0x8e, 0xa4, 0x54, 0x7c, 0x24, 0x2f, 0x41, 0x6e, 0xc0, + 0x02, 0xcf, 0xee, 0xf8, 0x78, 0x81, 0x62, 0xe3, 0x6a, 0x9c, 0x8e, 0xb3, 0xdc, 0x15, 0x04, 0x54, + 0x51, 0x92, 0xbb, 0x90, 0xf5, 0x03, 0x2b, 0x18, 0xf9, 0x78, 0xad, 0xb9, 0xc6, 0xd3, 0x93, 0x7b, + 0x94, 0x18, 0xf5, 0x16, 0x12, 0x52, 0xb9, 0x81, 0x6b, 0x73, 0xc0, 0x7c, 0xdf, 0xea, 0xb1, 0x6a, + 0x1a, 0x6f, 0xad, 0x40, 0xf3, 0x19, 0xc8, 0x0a, 0x5a, 0x52, 0x82, 0xfc, 0xbd, 0xfd, 0xdd, 0x83, + 0x9d, 0x66, 0xbb, 0x59, 0x99, 0x21, 0x45, 0xc8, 0x1d, 0x6c, 0xd0, 0xf6, 0xf6, 0xc6, 0x4e, 0xc5, + 0x30, 0x89, 0x66, 0x20, 0x29, 0x96, 0xf9, 0xf1, 0x2c, 0x94, 0x5b, 0xcc, 0xf2, 0x3a, 0x0f, 0x95, + 0xc9, 0x5e, 0x85, 0x74, 0xdb, 0xea, 0xf9, 0x55, 0x63, 0x25, 0xb5, 0x5a, 0x6c, 0xac, 0x84, 0xd2, + 0xc5, 0xa8, 0xea, 0x9c, 0xa4, 0xe9, 0x04, 0xde, 0xd9, 0x66, 0xfa, 0xa3, 0xcf, 0x6e, 0xcc, 0x50, + 0xdc, 0x43, 0x6e, 0x42, 0x79, 0xd7, 0x76, 0xb6, 0x46, 0x9e, 0x15, 0xd8, 0xae, 0xb3, 0x2b, 0xd4, + 0x52, 0xa6, 0x71, 0x24, 0x52, 0x59, 0x8f, 0x34, 0xaa, 0x94, 0xa4, 0xd2, 0x91, 0x64, 0x11, 0x32, + 0x3b, 0xf6, 0xc0, 0x0e, 0xf0, 0xaa, 0x65, 0x2a, 0x00, 0x8e, 0xf5, 0xd1, 0x63, 0x32, 0x02, 0x8b, + 0x00, 0xa9, 0x40, 0x8a, 0x39, 0x5d, 0x34, 0x72, 0x99, 0xf2, 0x25, 0xa7, 0x7b, 0x9b, 0x7b, 0x44, + 0x35, 0x8f, 0x8a, 0x12, 0x00, 0x59, 0x85, 0xf9, 0xd6, 0xd0, 0x72, 0xfc, 0x03, 0xe6, 0xf1, 0xbf, + 0x2d, 0x16, 0x54, 0x0b, 0xb8, 0x67, 0x1c, 0x5d, 0x7b, 0x19, 0x0a, 0xe1, 0x15, 0x39, 0xfb, 0x13, + 0x76, 0x86, 0xbe, 0x50, 0xa0, 0x7c, 0xc9, 0xd9, 0x9f, 0x5a, 0xfd, 0x11, 0x93, 0x8e, 0x2b, 0x80, + 0x57, 0x67, 0x5f, 0x31, 0xcc, 0xbf, 0xa6, 0x80, 0x08, 0x55, 0x6d, 0x72, 0x77, 0x55, 0x5a, 0xbd, + 0x0d, 0x05, 0x5f, 0x29, 0x50, 0x3a, 0xd5, 0x52, 0xb2, 0x6a, 0x69, 0x44, 0xc8, 0x0d, 0x8e, 0x4e, + 0xbf, 0xbd, 0x25, 0x0f, 0x52, 0x20, 0x0f, 0x01, 0xbc, 0xfa, 0x01, 0x77, 0x06, 0xa1, 0xbf, 0x08, + 0xc1, 0x35, 0x3c, 0xb4, 0x7a, 0xcc, 0x6f, 0xbb, 0x82, 0xb5, 0xd4, 0x61, 0x1c, 0xc9, 0x43, 0x8c, + 0x39, 0x1d, 0xb7, 0x6b, 0x3b, 0x3d, 0x19, 0x45, 0x21, 0xcc, 0x39, 0xd8, 0x4e, 0x97, 0x3d, 0xe2, + 0xec, 0x5a, 0xf6, 0x8f, 0x99, 0xd4, 0x6d, 0x1c, 0x49, 0x4c, 0x28, 0x05, 0x6e, 0x60, 0xf5, 0x29, + 0xeb, 0xb8, 0x5e, 0xd7, 0xaf, 0xe6, 0x90, 0x28, 0x86, 0xe3, 0x34, 0x5d, 0x2b, 0xb0, 0x9a, 0xea, + 0x24, 0x61, 0x90, 0x18, 0x8e, 0xdf, 0xf3, 0x94, 0x79, 0xbe, 0xed, 0x3a, 0x68, 0x8f, 0x02, 0x55, + 0x20, 0x21, 0x90, 0xf6, 0xf9, 0xf1, 0xb0, 0x62, 0xac, 0xa6, 0x29, 0xae, 0x79, 0xea, 0x78, 0xe0, + 0xba, 0x01, 0xf3, 0x50, 0xb0, 0x22, 0x9e, 0xa9, 0x61, 0xc8, 0x16, 0x54, 0xba, 0xac, 0x6b, 0x77, + 0xac, 0x80, 0x75, 0xef, 0xb9, 0xfd, 0xd1, 0xc0, 0xf1, 0xab, 0x25, 0xf4, 0xe6, 0x6a, 0xa8, 0xf2, + 0xad, 0x38, 0x01, 0x9d, 0xd8, 0x61, 0xfe, 0xc5, 0x80, 0xf9, 0x31, 0x2a, 0x72, 0x1b, 0x32, 0x7e, + 0xc7, 0x1d, 0x32, 0x19, 0xba, 0xcb, 0xd3, 0xd8, 0xd5, 0x5b, 0x9c, 0x8a, 0x0a, 0x62, 0x7e, 0x07, + 0xc7, 0x1a, 0x28, 0x5f, 0xc1, 0x35, 0xb9, 0x05, 0xe9, 0xe0, 0x6c, 0x28, 0xf2, 0xcb, 0x5c, 0xe3, + 0xa9, 0xa9, 0x8c, 0xda, 0x67, 0x43, 0x46, 0x91, 0xd4, 0xbc, 0x01, 0x19, 0x64, 0x4b, 0xf2, 0x90, + 0x6e, 0x1d, 0x6c, 0xec, 0x55, 0x66, 0x78, 0xb0, 0xd3, 0x66, 0x6b, 0xff, 0x1d, 0x7a, 0xaf, 0x89, + 0xf1, 0x9d, 0xe6, 0xe4, 0x04, 0x20, 0xdb, 0x6a, 0xd3, 0xed, 0xbd, 0xfb, 0x95, 0x19, 0xf3, 0x11, + 0xcc, 0x29, 0xef, 0x92, 0xa9, 0xed, 0x36, 0x64, 0x31, 0x7b, 0xa9, 0x08, 0xbf, 0x1e, 0xcf, 0x3f, + 0x82, 0x7a, 0x97, 0x05, 0x16, 0xb7, 0x10, 0x95, 0xb4, 0x64, 0x7d, 0x3c, 0xd5, 0x8d, 0x7b, 0xef, + 0x78, 0x9e, 0x33, 0xff, 0x91, 0x82, 0x2b, 0x09, 0x1c, 0xc7, 0x4b, 0x42, 0x21, 0x2a, 0x09, 0xab, + 0x30, 0xef, 0xb9, 0x6e, 0xd0, 0x62, 0xde, 0xa9, 0xdd, 0x61, 0x7b, 0x91, 0xca, 0xc6, 0xd1, 0xdc, + 0x3b, 0x39, 0x0a, 0xd9, 0x23, 0x9d, 0xa8, 0x10, 0x71, 0x24, 0x2f, 0x04, 0x18, 0x12, 0x6d, 0x7b, + 0xc0, 0xde, 0x71, 0xec, 0x47, 0x7b, 0x96, 0xe3, 0x62, 0x24, 0xa4, 0xe9, 0xe4, 0x07, 0xee, 0x55, + 0xdd, 0x28, 0x25, 0x89, 0xf4, 0xa2, 0x61, 0xc8, 0x73, 0x90, 0xf3, 0x65, 0xce, 0xc8, 0xa2, 0x06, + 0x2a, 0x91, 0x06, 0x04, 0x9e, 0x2a, 0x02, 0xf2, 0x02, 0xe4, 0xe5, 0x92, 0xc7, 0x44, 0x2a, 0x91, + 0x38, 0xa4, 0x20, 0x14, 0x4a, 0xbe, 0xb8, 0x1c, 0xcf, 0xe1, 0x7e, 0x35, 0x8f, 0x3b, 0xea, 0xe7, + 0xd9, 0xa5, 0xde, 0xd2, 0x36, 0x60, 0x92, 0xa2, 0x31, 0x1e, 0xb5, 0x43, 0x58, 0x98, 0x20, 0x49, + 0xc8, 0x63, 0xcf, 0xeb, 0x79, 0xac, 0xd8, 0x78, 0x42, 0x33, 0x6a, 0xb4, 0x59, 0x4f, 0x6f, 0x3b, + 0x50, 0xd2, 0x3f, 0x61, 0x1e, 0x1a, 0x5a, 0xce, 0x3d, 0x77, 0xe4, 0x04, 0xc8, 0x98, 0xe7, 0x21, + 0x85, 0xe0, 0x3a, 0x65, 0x9e, 0xe7, 0x7a, 0xe2, 0xb3, 0x28, 0x06, 0x1a, 0xc6, 0xfc, 0xb9, 0x01, + 0x39, 0xa9, 0x0f, 0xf2, 0x0c, 0x64, 0xf8, 0x46, 0xe5, 0x96, 0xe5, 0x98, 0xc2, 0xa8, 0xf8, 0x86, + 0x15, 0xd0, 0x0a, 0x3a, 0x0f, 0x59, 0x57, 0x72, 0x53, 0x20, 0x79, 0x0d, 0xc0, 0x0a, 0x02, 0xcf, + 0x3e, 0x1e, 0x05, 0x8c, 0x57, 0x14, 0xce, 0xe3, 0x5a, 0xc8, 0x43, 0xb6, 0x3b, 0xa7, 0xb7, 0xea, + 0x6f, 0xb1, 0xb3, 0x43, 0x7e, 0x1b, 0xaa, 0x91, 0xf3, 0x58, 0x4f, 0xf3, 0x63, 0xc8, 0x12, 0x64, + 0xf9, 0x41, 0xa1, 0x6f, 0x4a, 0x28, 0x31, 0x84, 0x13, 0xdd, 0x2b, 0x35, 0xcd, 0xbd, 0x6e, 0x42, + 0x59, 0x39, 0x13, 0x87, 0x7d, 0xe9, 0x88, 0x71, 0xe4, 0xd8, 0x2d, 0x32, 0x8f, 0x77, 0x8b, 0xdf, + 0x86, 0xb5, 0x5c, 0x06, 0x23, 0x8f, 0x28, 0xdb, 0xf1, 0x87, 0xac, 0x13, 0xb0, 0x6e, 0x5b, 0x05, + 0x3d, 0xd6, 0xbb, 0x31, 0x34, 0x79, 0x16, 0xe6, 0x42, 0xd4, 0xe6, 0x19, 0x3f, 0x7c, 0x16, 0xe5, + 0x1b, 0xc3, 0x92, 0x15, 0x28, 0x62, 0x76, 0xc7, 0xe2, 0xa6, 0x2a, 0xb7, 0x8e, 0xe2, 0x17, 0xed, + 0xb8, 0x83, 0x61, 0x9f, 0x05, 0xac, 0xfb, 0xa6, 0x7b, 0xec, 0xab, 0xda, 0x13, 0x43, 0x72, 0xbf, + 0xc1, 0x4d, 0x48, 0x21, 0x82, 0x2d, 0x42, 0x70, 0xb9, 0x23, 0x96, 0x42, 0x9c, 0x2c, 0x8a, 0x33, + 0x8e, 0x8e, 0xc9, 0x8d, 0x35, 0x1c, 0x6b, 0x90, 0x2e, 0x37, 0x62, 0xcd, 0x1e, 0x8f, 0x07, 0xae, + 0x1a, 0x5e, 0xd5, 0x55, 0x51, 0x5e, 0x54, 0xe9, 0x5c, 0x18, 0x5b, 0xa6, 0xeb, 0x45, 0xc8, 0x60, + 0x33, 0xa9, 0x6a, 0x3b, 0x02, 0x51, 0xe3, 0x91, 0x4a, 0x68, 0x3c, 0xd2, 0x61, 0xe3, 0x61, 0x7e, + 0x9c, 0x82, 0xa5, 0xe8, 0xa4, 0x58, 0x0f, 0xf0, 0xca, 0x64, 0x0f, 0x50, 0x1b, 0xcb, 0xa2, 0x9a, + 0x74, 0xdf, 0xf6, 0x01, 0xdf, 0x8c, 0x3e, 0xe0, 0xd3, 0x14, 0x5c, 0x0b, 0x8d, 0x83, 0x41, 0x17, + 0xb7, 0xea, 0xf7, 0x27, 0xad, 0x7a, 0x63, 0xd2, 0xaa, 0x62, 0xe3, 0xb7, 0xa6, 0xfd, 0x46, 0x99, + 0x76, 0x5d, 0xb5, 0xea, 0x22, 0xec, 0x64, 0x83, 0x54, 0x83, 0x7c, 0x60, 0xf5, 0x78, 0x07, 0x21, + 0x6a, 0x51, 0x81, 0x86, 0xb0, 0xf9, 0x26, 0x2c, 0x46, 0x3b, 0x0e, 0x1b, 0xe1, 0x9e, 0x06, 0x64, + 0x31, 0x79, 0xa8, 0xea, 0x95, 0x14, 0xd7, 0x87, 0x0d, 0xd1, 0x15, 0x4a, 0x4a, 0xf3, 0x35, 0x3d, + 0x25, 0xc9, 0x8f, 0x61, 0xa1, 0x31, 0xb4, 0x42, 0x43, 0x20, 0x1d, 0xf0, 0x89, 0x6c, 0x16, 0x85, + 0xc1, 0xb5, 0x39, 0xd4, 0xb2, 0x4c, 0xcc, 0xb7, 0xb0, 0xbf, 0x12, 0xe2, 0x86, 0xfd, 0x95, 0x00, + 0x2f, 0x4a, 0x6c, 0xe9, 0x84, 0xc4, 0x96, 0x89, 0x12, 0xdb, 0xcb, 0xf0, 0xe4, 0xc4, 0x89, 0xf2, + 0xf6, 0x3c, 0x99, 0x2b, 0xa4, 0x54, 0x59, 0x84, 0x30, 0x6f, 0x43, 0x5e, 0x6d, 0xc1, 0xab, 0x9c, + 0x85, 0x09, 0x17, 0xd7, 0xc9, 0xb3, 0x94, 0xb9, 0x03, 0x57, 0xc7, 0x8e, 0xd3, 0xd4, 0xbd, 0x36, + 0x7e, 0x60, 0xb1, 0xb1, 0x10, 0xb5, 0x4b, 0xf2, 0x8b, 0x2e, 0xc3, 0x1e, 0x64, 0xb0, 0xd0, 0x91, + 0x26, 0x94, 0x3d, 0xe6, 0xbb, 0x23, 0xaf, 0xc3, 0x5a, 0x5a, 0xb7, 0x11, 0x45, 0xac, 0x78, 0xd2, + 0x38, 0xbd, 0x55, 0xa7, 0x3a, 0x19, 0x8d, 0xef, 0x32, 0xf7, 0xa0, 0x74, 0x30, 0xf2, 0xa3, 0xa6, + 0xfa, 0x75, 0x28, 0x63, 0x5b, 0xe3, 0x6f, 0x9e, 0xb5, 0xe5, 0xbb, 0x41, 0x6a, 0x75, 0x4e, 0x73, + 0x46, 0x4e, 0xdd, 0xe4, 0x14, 0x94, 0x59, 0xbe, 0xeb, 0xd0, 0x38, 0xb9, 0xf9, 0x3b, 0x03, 0x2a, + 0x9c, 0x04, 0x8b, 0x9a, 0xb2, 0xe4, 0x8b, 0x61, 0xa7, 0xce, 0x2d, 0x5f, 0xda, 0x7c, 0x82, 0x4f, + 0xda, 0xff, 0xfc, 0xec, 0x46, 0xf9, 0xc0, 0x63, 0x56, 0xbf, 0xef, 0x76, 0x04, 0xb5, 0x6a, 0xd1, + 0xbf, 0x03, 0x29, 0xbb, 0x2b, 0x5a, 0x9f, 0xa9, 0xb4, 0x9c, 0x82, 0xdc, 0x01, 0x10, 0xf9, 0x67, + 0xcb, 0x0a, 0xac, 0x6a, 0xfa, 0x3c, 0x7a, 0x8d, 0xd0, 0xdc, 0x15, 0x22, 0x0a, 0x7d, 0x48, 0x11, + 0xef, 0x42, 0xee, 0x18, 0x1b, 0xb0, 0x2f, 0xad, 0x48, 0x45, 0x6f, 0xde, 0x04, 0x90, 0xaf, 0x11, + 0xbc, 0x8e, 0x2f, 0xc5, 0xa6, 0x92, 0x92, 0xba, 0x94, 0xf9, 0x3a, 0x14, 0x76, 0x6c, 0xe7, 0xa4, + 0xd5, 0xb7, 0x3b, 0x7c, 0x68, 0xca, 0xf4, 0x6d, 0xe7, 0x44, 0x9d, 0x75, 0x6d, 0xf2, 0x2c, 0x7e, + 0x46, 0x9d, 0x6f, 0xa0, 0x82, 0xd2, 0xfc, 0x99, 0x01, 0x84, 0x23, 0xd5, 0x78, 0x12, 0x55, 0x7e, + 0x11, 0x0a, 0x86, 0x1e, 0x0a, 0x55, 0xc8, 0xf5, 0x3c, 0x77, 0x34, 0xdc, 0x54, 0x21, 0xa2, 0x40, + 0x4e, 0xdf, 0xc7, 0xc7, 0x08, 0xd1, 0xdf, 0x09, 0xe0, 0x4b, 0x87, 0xce, 0x2f, 0x0c, 0xb8, 0xaa, + 0x09, 0xd1, 0x1a, 0x0d, 0x06, 0x96, 0x77, 0xf6, 0xff, 0x91, 0xe5, 0x0f, 0x06, 0x5c, 0x89, 0x29, + 0x24, 0x8a, 0x61, 0xe6, 0x07, 0xf6, 0x80, 0xe7, 0x47, 0x94, 0x24, 0x4f, 0x23, 0x44, 0xbc, 0xcd, + 0x17, 0x9d, 0xa1, 0xd6, 0xe6, 0x3f, 0x0b, 0x73, 0xe8, 0xce, 0xad, 0x90, 0x44, 0x88, 0x36, 0x86, + 0x25, 0xf5, 0x68, 0x88, 0x4c, 0xa3, 0x05, 0x17, 0x63, 0x4d, 0xfe, 0xc4, 0x08, 0xf9, 0x3d, 0x28, + 0x51, 0xeb, 0xc3, 0x37, 0x6c, 0x3f, 0x70, 0x7b, 0x9e, 0x35, 0xe0, 0x4e, 0x72, 0x3c, 0xea, 0x9c, + 0x30, 0x31, 0x69, 0xa4, 0xa9, 0x84, 0xf8, 0xdd, 0x3b, 0x9a, 0x64, 0x02, 0x30, 0xdf, 0x84, 0xbc, + 0x6a, 0x93, 0x13, 0x26, 0x9f, 0x17, 0xe2, 0x93, 0xcf, 0x52, 0x7c, 0xda, 0x7a, 0x7b, 0x87, 0x8f, + 0x37, 0x76, 0x47, 0x65, 0xa3, 0x5f, 0x1b, 0x50, 0xd4, 0x44, 0x24, 0x9b, 0xb0, 0xd0, 0xb7, 0x02, + 0xe6, 0x74, 0xce, 0x8e, 0x1e, 0x2a, 0xf1, 0xa4, 0x57, 0x46, 0x33, 0x94, 0x2e, 0x3b, 0xad, 0x48, + 0xfa, 0xe8, 0x36, 0xdf, 0x85, 0xac, 0xcf, 0x3c, 0x5b, 0x86, 0xb7, 0x9e, 0xc1, 0xc2, 0xee, 0x5e, + 0x12, 0xf0, 0x8b, 0x8b, 0x7c, 0x21, 0x15, 0x2b, 0x21, 0xf3, 0xef, 0x71, 0xef, 0x96, 0x8e, 0x35, + 0x39, 0x94, 0x5d, 0x60, 0xad, 0xd9, 0x44, 0x6b, 0x45, 0xf2, 0xa5, 0x2e, 0x92, 0xaf, 0x02, 0xa9, + 0xe1, 0xdd, 0xbb, 0x72, 0xa4, 0xe1, 0x4b, 0x81, 0xb9, 0x83, 0x8e, 0x87, 0x98, 0x3b, 0x02, 0xb3, + 0x2e, 0xfb, 0x78, 0xbe, 0x44, 0xcc, 0x9d, 0x75, 0xd9, 0xb0, 0xf3, 0xa5, 0xf9, 0x2e, 0xd4, 0x92, + 0xe2, 0x44, 0xba, 0xe8, 0x5d, 0x28, 0xf8, 0x88, 0xb2, 0xd9, 0x64, 0x0a, 0x48, 0xd8, 0x17, 0x51, + 0x9b, 0xbf, 0x31, 0xa0, 0x1c, 0x33, 0x6c, 0xac, 0x12, 0x65, 0x64, 0x25, 0x2a, 0x81, 0xe1, 0xa0, + 0x32, 0x52, 0xd4, 0x70, 0x38, 0xf4, 0x00, 0xf5, 0x6d, 0x50, 0xe3, 0x01, 0x87, 0x7c, 0xf9, 0xea, + 0x6a, 0xf8, 0x1c, 0x3a, 0xc6, 0xcb, 0xe5, 0xa9, 0x71, 0xcc, 0xa1, 0xae, 0xbc, 0x98, 0xd1, 0xc5, + 0x19, 0x52, 0x3c, 0xf0, 0xe6, 0x90, 0xb7, 0x7a, 0xbd, 0x25, 0x90, 0x3e, 0xb1, 0x9d, 0x2e, 0x76, + 0x47, 0x19, 0x8a, 0x6b, 0x93, 0x89, 0x07, 0x49, 0x29, 0x38, 0x4f, 0xb3, 0xbc, 0xf5, 0xf1, 0x98, + 0x3f, 0xea, 0x07, 0xed, 0xa8, 0x50, 0x6a, 0x18, 0xde, 0x6a, 0x08, 0x48, 0xba, 0x4d, 0x2d, 0x31, + 0x86, 0x90, 0x82, 0x4a, 0x4a, 0x9e, 0x05, 0x17, 0x26, 0xbe, 0x72, 0x37, 0xe9, 0x5b, 0xc7, 0xac, + 0xaf, 0xf5, 0x0a, 0x11, 0x82, 0xcb, 0x81, 0xc0, 0xa1, 0x56, 0x9b, 0x35, 0x0c, 0x59, 0x83, 0xd9, + 0x40, 0xb9, 0xc6, 0x8d, 0xe9, 0x32, 0x1c, 0xb8, 0xb6, 0x13, 0xd0, 0xd9, 0xc0, 0xe7, 0x31, 0xb4, + 0x94, 0xfc, 0x19, 0x8d, 0x61, 0x4b, 0x21, 0xca, 0x14, 0xd7, 0xdc, 0x3b, 0x4e, 0xad, 0x3e, 0x1e, + 0x6c, 0x50, 0xbe, 0xe4, 0x53, 0x21, 0x7b, 0xc4, 0x06, 0xc3, 0xbe, 0xe5, 0xb5, 0xe5, 0x0b, 0x52, + 0x0a, 0x7f, 0x54, 0x18, 0x47, 0x93, 0xe7, 0xa0, 0xa2, 0x50, 0xea, 0x45, 0x59, 0x3a, 0xe7, 0x04, + 0xde, 0x6c, 0xc1, 0x15, 0x7c, 0x1c, 0xde, 0x76, 0xfc, 0xc0, 0x72, 0x82, 0xf3, 0xb3, 0x72, 0x98, + 0x65, 0x65, 0xa6, 0x89, 0x65, 0x59, 0x11, 0x9b, 0x98, 0x65, 0x1f, 0xc1, 0x62, 0x9c, 0xa9, 0x74, + 0xe1, 0x7a, 0x18, 0x53, 0xc2, 0x7f, 0xa3, 0xb4, 0x23, 0x29, 0x5b, 0xf8, 0x35, 0x0c, 0xac, 0xc7, + 0x7f, 0x76, 0xfb, 0xa9, 0x01, 0xe5, 0x18, 0x2f, 0x72, 0x17, 0xb2, 0x68, 0xb6, 0xc9, 0x98, 0x99, + 0x7c, 0x4f, 0x90, 0xaf, 0xf9, 0x72, 0x43, 0xbc, 0x35, 0x33, 0x64, 0x32, 0x24, 0x37, 0xa0, 0x38, + 0xf4, 0xdc, 0xc1, 0x91, 0xe4, 0x2a, 0xde, 0xde, 0x80, 0xa3, 0x76, 0x10, 0x63, 0xfe, 0x31, 0x05, + 0x0b, 0x78, 0x7d, 0x6a, 0x39, 0x3d, 0x76, 0x29, 0x1a, 0xc5, 0x29, 0x21, 0x60, 0x43, 0x69, 0x46, + 0x5c, 0xc7, 0x7f, 0x07, 0xca, 0x8d, 0xff, 0x0e, 0xa4, 0x4d, 0x56, 0xf9, 0x73, 0x26, 0xab, 0xc2, + 0x85, 0x93, 0x15, 0x24, 0x4d, 0x56, 0xda, 0x3c, 0x53, 0x8c, 0xcf, 0x33, 0xfa, 0xcc, 0x55, 0x1a, + 0x9b, 0xb9, 0xd4, 0xac, 0x53, 0x9e, 0x3a, 0xeb, 0xcc, 0x7d, 0xa9, 0x59, 0x67, 0xfe, 0x71, 0x67, + 0x1d, 0xac, 0xef, 0xd2, 0xf5, 0xfd, 0x6a, 0x45, 0xdc, 0x39, 0x44, 0x98, 0x3e, 0x10, 0xdd, 0x60, + 0xd2, 0x5b, 0x9f, 0x1f, 0xf3, 0xd6, 0x2b, 0x51, 0x91, 0xb4, 0x07, 0xec, 0x2b, 0xbb, 0xea, 0x4f, + 0x20, 0xdf, 0x94, 0x12, 0x5c, 0xbe, 0x93, 0x3e, 0x0d, 0x25, 0x9e, 0x46, 0xfc, 0xc0, 0x1a, 0x0c, + 0x8f, 0x06, 0xc2, 0x4b, 0x53, 0xb4, 0x18, 0xe2, 0x76, 0x7d, 0x73, 0x03, 0xb2, 0x2d, 0x6b, 0x30, + 0xec, 0x4f, 0x12, 0xcf, 0x4e, 0x10, 0x47, 0xa7, 0x18, 0xda, 0x29, 0xe6, 0x27, 0x06, 0x40, 0xa4, + 0x8b, 0xaf, 0x72, 0x8b, 0x35, 0xc8, 0xf9, 0x28, 0x8c, 0x6a, 0x07, 0xe6, 0x23, 0xf5, 0x21, 0x5e, + 0xd2, 0x2b, 0xaa, 0x0b, 0xa3, 0x90, 0xdc, 0xd1, 0x2d, 0x9e, 0x1e, 0x2b, 0xe1, 0x4a, 0xf1, 0x92, + 0x6b, 0x44, 0xf9, 0xdc, 0xfb, 0x30, 0x3f, 0x36, 0xac, 0x90, 0x12, 0xe4, 0xf7, 0xf6, 0x8f, 0x9a, + 0x94, 0xee, 0xd3, 0xca, 0x0c, 0xb9, 0x02, 0xf3, 0xbb, 0x1b, 0xef, 0x1d, 0xed, 0x6c, 0x1f, 0x36, + 0x8f, 0xda, 0x74, 0xe3, 0x5e, 0xb3, 0x55, 0x31, 0x38, 0x12, 0xd7, 0x47, 0xed, 0xfd, 0xfd, 0xa3, + 0x9d, 0x0d, 0x7a, 0xbf, 0x59, 0x99, 0x25, 0x0b, 0x50, 0x7e, 0x67, 0xef, 0xad, 0xbd, 0xfd, 0x77, + 0xf7, 0xe4, 0xe6, 0x54, 0xe3, 0x97, 0x06, 0x64, 0x39, 0x7b, 0xe6, 0x91, 0x1f, 0x40, 0x21, 0x1c, + 0x79, 0xc8, 0xd5, 0xd8, 0xa4, 0xa4, 0x8f, 0x41, 0xb5, 0x27, 0x62, 0x9f, 0x94, 0x73, 0x9a, 0x33, + 0x64, 0x03, 0x8a, 0x21, 0xf1, 0x61, 0xe3, 0x7f, 0x61, 0xd1, 0xf8, 0xb7, 0x01, 0x15, 0xe9, 0x97, + 0xf7, 0x99, 0xc3, 0x3c, 0x2b, 0x70, 0x43, 0xc1, 0x70, 0x5e, 0x19, 0xe3, 0xaa, 0x0f, 0x3f, 0xd3, + 0x05, 0xdb, 0x06, 0xb8, 0xcf, 0x02, 0xd5, 0x2b, 0x5e, 0x4b, 0x2e, 0x8e, 0x82, 0xc7, 0xf5, 0x29, + 0x95, 0x53, 0xb1, 0xba, 0x0f, 0x10, 0x05, 0x26, 0x89, 0x6a, 0xfd, 0x44, 0x7a, 0xad, 0x5d, 0x4b, + 0xfc, 0x16, 0xde, 0xf4, 0xf7, 0x69, 0xc8, 0xf1, 0x0f, 0x36, 0xf3, 0xc8, 0x1b, 0x50, 0xfe, 0xa1, + 0xed, 0x74, 0xc3, 0x1f, 0x83, 0xc9, 0xd5, 0xa4, 0xdf, 0xa0, 0x05, 0xdb, 0xda, 0xf4, 0x9f, 0xa7, + 0xd1, 0x04, 0x25, 0xf5, 0xf3, 0x52, 0x87, 0x39, 0x01, 0x99, 0xf2, 0x9b, 0x66, 0xed, 0xc9, 0x09, + 0x7c, 0xc8, 0xa2, 0x09, 0x45, 0xed, 0xf7, 0x52, 0x5d, 0x5b, 0x13, 0xbf, 0xa2, 0x9e, 0xc7, 0xe6, + 0x3e, 0x40, 0xf4, 0x9a, 0x42, 0xce, 0x79, 0x57, 0xad, 0x5d, 0x4b, 0xfc, 0x16, 0x32, 0x7a, 0x4b, + 0x5d, 0x49, 0x3c, 0xcb, 0x9c, 0xcb, 0xea, 0xa9, 0xc4, 0x67, 0x1e, 0x8d, 0xd9, 0x21, 0xcc, 0x8f, + 0xbd, 0x62, 0x90, 0x8b, 0x1e, 0x07, 0x6b, 0x2b, 0xd3, 0x09, 0x42, 0xbe, 0x3f, 0xd2, 0xde, 0x8e, + 0xd4, 0xeb, 0xc8, 0xc5, 0x9c, 0xcd, 0x69, 0x04, 0xba, 0xcc, 0x8d, 0xbf, 0xa5, 0xa1, 0xd2, 0x0a, + 0x3c, 0x66, 0x0d, 0x6c, 0xa7, 0xa7, 0x5c, 0xe6, 0x35, 0xc8, 0xca, 0xc2, 0xf7, 0xb8, 0x26, 0x5e, + 0x37, 0x78, 0x3c, 0x5c, 0x8a, 0x6d, 0xd6, 0x0d, 0xb2, 0x7b, 0x89, 0xd6, 0x59, 0x37, 0xc8, 0x7b, + 0x5f, 0x8f, 0x7d, 0xd6, 0x0d, 0xf2, 0xfe, 0xd7, 0x67, 0xa1, 0x75, 0x83, 0x1c, 0xc0, 0x82, 0xcc, + 0x15, 0x97, 0x92, 0x1d, 0xd6, 0x0d, 0x72, 0x08, 0x57, 0x74, 0x8e, 0xb2, 0x85, 0x24, 0xd7, 0xe3, + 0xfb, 0xe2, 0x4d, 0xb2, 0xa6, 0xe1, 0xa4, 0x6e, 0x97, 0xf3, 0x6d, 0xfc, 0xc9, 0x80, 0x9c, 0xca, + 0x84, 0x47, 0x89, 0xd3, 0xaa, 0x79, 0xde, 0x0c, 0x27, 0x0f, 0x7a, 0xe6, 0x5c, 0x9a, 0x4b, 0xcf, + 0x96, 0x9b, 0xd5, 0x8f, 0x3e, 0x5f, 0x36, 0x3e, 0xf9, 0x7c, 0xd9, 0xf8, 0xd7, 0xe7, 0xcb, 0xc6, + 0xaf, 0xbe, 0x58, 0x9e, 0xf9, 0xe4, 0x8b, 0xe5, 0x99, 0x4f, 0xbf, 0x58, 0x9e, 0x39, 0xce, 0xe2, + 0x7f, 0x3b, 0xbd, 0xf4, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdc, 0xc4, 0xa8, 0xe6, 0x6e, 0x25, + 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/pkg/tempopb/tempo.proto b/pkg/tempopb/tempo.proto index 5e0ab101371..5acd1ad612f 100644 --- a/pkg/tempopb/tempo.proto +++ b/pkg/tempopb/tempo.proto @@ -2,8 +2,6 @@ syntax = "proto3"; package tempopb; -option go_package = "github.com/grafana/tempo/pkg/tempopb"; - import "common/v1/common.proto"; import "github.com/gogo/protobuf/gogoproto/gogo.proto"; import "trace/v1/trace.proto"; From a23e192d8ccb4d885ab166ba0a1883351a7c9e0f Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Mon, 23 Sep 2024 20:43:26 +0000 Subject: [PATCH 44/71] Improve encoding marshal performance --- tempodb/backend/encoding.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tempodb/backend/encoding.go b/tempodb/backend/encoding.go index b715ab324b1..ea28f7ff059 100644 --- a/tempodb/backend/encoding.go +++ b/tempodb/backend/encoding.go @@ -110,12 +110,8 @@ func (e Encoding) Marshal() ([]byte, error) { } func (e *Encoding) MarshalTo(data []byte) (n int, err error) { - b, err := e.Marshal() - if err != nil { - return 0, err - } - - return copy(data, b), nil + data[0] = byte(*e) + return 1, nil } func (e *Encoding) Unmarshal(data []byte) error { From fb17a1c8cc882946eba5512db0e4106fc6bfc679 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Tue, 24 Sep 2024 18:32:13 +0000 Subject: [PATCH 45/71] Drop block proto and tenantindex json --- tempodb/backend/azure/azure.go | 3 -- tempodb/backend/azure/compactor.go | 51 +------------------ tempodb/backend/gcs/compactor.go | 52 ++------------------ tempodb/backend/gcs/gcs.go | 4 -- tempodb/backend/local/compactor.go | 43 ---------------- tempodb/backend/local/local.go | 4 -- tempodb/backend/mocks.go | 6 +-- tempodb/backend/raw.go | 73 ++------------------------- tempodb/backend/raw_test.go | 79 ++++++++++++++++-------------- tempodb/backend/s3/compactor.go | 52 ++------------------ tempodb/backend/s3/s3.go | 4 +- tempodb/backend/tenantindex.go | 8 +++ 12 files changed, 68 insertions(+), 311 deletions(-) diff --git a/tempodb/backend/azure/azure.go b/tempodb/backend/azure/azure.go index 782d10d7b3e..fc4c7f64940 100644 --- a/tempodb/backend/azure/azure.go +++ b/tempodb/backend/azure/azure.go @@ -19,7 +19,6 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blockblob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container" - gkLog "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/google/uuid" "github.com/grafana/tempo/pkg/util/log" @@ -37,7 +36,6 @@ const ( ) type Azure struct { - logger gkLog.Logger cfg *Config containerClient *container.Client hedgedContainerClient *container.Client @@ -97,7 +95,6 @@ func internalNew(cfg *Config, confirm bool) (*Azure, error) { } rw := &Azure{ - logger: log.Logger, cfg: cfg, containerClient: c, hedgedContainerClient: hedgedContainer, diff --git a/tempodb/backend/azure/compactor.go b/tempodb/backend/azure/compactor.go index 6eaa7e814e9..4c2c494e63c 100644 --- a/tempodb/backend/azure/compactor.go +++ b/tempodb/backend/azure/compactor.go @@ -8,7 +8,6 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container" - "github.com/go-kit/log/level" "github.com/google/uuid" "github.com/grafana/tempo/tempodb/backend" @@ -30,30 +29,10 @@ func (rw *Azure) MarkBlockCompacted(blockID uuid.UUID, tenantID string) error { return backend.ErrEmptyBlockID } - ctx := context.TODO() - - // move meta files to a new location - metaFilenamePb := backend.MetaFileNamePb(blockID, tenantID, rw.cfg.Prefix) - compactedMetaFilenamePb := backend.CompactedMetaFileNamePb(blockID, tenantID, rw.cfg.Prefix) - - srcPb, _, err := rw.readAll(ctx, metaFilenamePb) - if err != nil { - level.Error(rw.logger).Log("msg", "error copying obj meta.pb to compacted.pb, is this block from previous Tempo version?", "err", err) - } else { - err = rw.writeAll(ctx, compactedMetaFilenamePb, srcPb) - if err != nil { - return err - } - - // delete the old file - err = rw.Delete(ctx, metaFilenamePb, []string{}, nil) - if err != nil { - return err - } - } - + // move meta file to a new location metaFilename := backend.MetaFileName(blockID, tenantID, rw.cfg.Prefix) compactedMetaFilename := backend.CompactedMetaFileName(blockID, tenantID, rw.cfg.Prefix) + ctx := context.TODO() src, _, err := rw.readAll(ctx, metaFilename) if err != nil { @@ -117,14 +96,6 @@ func (rw *Azure) CompactedBlockMeta(blockID uuid.UUID, tenantID string) (*backen if blockID == uuid.Nil { return nil, backend.ErrEmptyBlockID } - - outPb, err := rw.compactedBlockMetaPb(blockID, tenantID) - if err == nil { - return outPb, nil - } - - // TODO: record a note about the fallback - name := backend.CompactedMetaFileName(blockID, tenantID, rw.cfg.Prefix) bytes, modTime, err := rw.readAllWithModTime(context.Background(), name) @@ -142,24 +113,6 @@ func (rw *Azure) CompactedBlockMeta(blockID uuid.UUID, tenantID string) (*backen return out, nil } -func (rw *Azure) compactedBlockMetaPb(blockID uuid.UUID, tenantID string) (*backend.CompactedBlockMeta, error) { - name := backend.CompactedMetaFileNamePb(blockID, tenantID, rw.cfg.Prefix) - - bytes, modTime, err := rw.readAllWithModTime(context.Background(), name) - if err != nil { - return nil, readError(err) - } - - out := &backend.CompactedBlockMeta{} - err = out.Unmarshal(bytes) - if err != nil { - return nil, err - } - out.CompactedTime = modTime - - return out, nil -} - func (rw *Azure) readAllWithModTime(ctx context.Context, name string) ([]byte, time.Time, error) { bytes, _, err := rw.readAll(ctx, name) if err != nil { diff --git a/tempodb/backend/gcs/compactor.go b/tempodb/backend/gcs/compactor.go index cb94867bbfc..a02c1ff32f3 100644 --- a/tempodb/backend/gcs/compactor.go +++ b/tempodb/backend/gcs/compactor.go @@ -7,7 +7,6 @@ import ( "fmt" "cloud.google.com/go/storage" - "github.com/go-kit/log/level" "github.com/google/uuid" "github.com/googleapis/gax-go/v2" "google.golang.org/api/iterator" @@ -16,28 +15,7 @@ import ( ) func (rw *readerWriter) MarkBlockCompacted(blockID uuid.UUID, tenantID string) error { - // move meta files to a new location - - metaFilenamePb := backend.MetaFileNamePb(blockID, tenantID, rw.cfg.Prefix) - compactedMetaFilenamePb := backend.CompactedMetaFileNamePb(blockID, tenantID, rw.cfg.Prefix) - - srcPb := rw.bucket.Object(metaFilenamePb) - dstPb := rw.bucket.Object(compactedMetaFilenamePb).Retryer( - storage.WithBackoff(gax.Backoff{}), - storage.WithPolicy(storage.RetryAlways), - ) - - ctx := context.TODO() - _, err := dstPb.CopierFrom(srcPb).Run(ctx) - if err != nil { - level.Error(rw.logger).Log("msg", "error copying obj meta.pb to compacted.pb, is this block from previous Tempo version?", "err", err) - } else { - err = srcPb.Delete(ctx) - if err != nil { - return err - } - } - + // move meta file to a new location metaFilename := backend.MetaFileName(blockID, tenantID, rw.cfg.Prefix) compactedMetaFilename := backend.CompactedMetaFileName(blockID, tenantID, rw.cfg.Prefix) @@ -47,7 +25,8 @@ func (rw *readerWriter) MarkBlockCompacted(blockID uuid.UUID, tenantID string) e storage.WithPolicy(storage.RetryAlways), ) - _, err = dst.CopierFrom(src).Run(ctx) + ctx := context.TODO() + _, err := dst.CopierFrom(src).Run(ctx) if err != nil { return err } @@ -90,13 +69,6 @@ func (rw *readerWriter) ClearBlock(blockID uuid.UUID, tenantID string) error { } func (rw *readerWriter) CompactedBlockMeta(blockID uuid.UUID, tenantID string) (*backend.CompactedBlockMeta, error) { - outPb, err := rw.compactedBlockMetaPb(blockID, tenantID) - if err == nil { - return outPb, nil - } - - // TODO: record a note about fallback - name := backend.CompactedMetaFileName(blockID, tenantID, rw.cfg.Prefix) bytes, attrs, err := rw.readAll(context.Background(), name) @@ -113,21 +85,3 @@ func (rw *readerWriter) CompactedBlockMeta(blockID uuid.UUID, tenantID string) ( return out, nil } - -func (rw *readerWriter) compactedBlockMetaPb(blockID uuid.UUID, tenantID string) (*backend.CompactedBlockMeta, error) { - name := backend.CompactedMetaFileNamePb(blockID, tenantID, rw.cfg.Prefix) - - bytes, attrs, err := rw.readAll(context.Background(), name) - if err != nil { - return nil, readError(err) - } - - out := &backend.CompactedBlockMeta{} - err = out.Unmarshal(bytes) - if err != nil { - return nil, err - } - out.CompactedTime = attrs.LastModified - - return out, nil -} diff --git a/tempodb/backend/gcs/gcs.go b/tempodb/backend/gcs/gcs.go index c47d40cbe0e..aacb3072fe6 100644 --- a/tempodb/backend/gcs/gcs.go +++ b/tempodb/backend/gcs/gcs.go @@ -23,19 +23,16 @@ import ( "cloud.google.com/go/storage" "github.com/cristalhq/hedgedhttp" - gkLog "github.com/go-kit/log" "google.golang.org/api/iterator" "google.golang.org/api/option" google_http "google.golang.org/api/transport/http" "github.com/grafana/tempo/pkg/blockboundary" tempo_io "github.com/grafana/tempo/pkg/io" - "github.com/grafana/tempo/pkg/util/log" "github.com/grafana/tempo/tempodb/backend" ) type readerWriter struct { - logger gkLog.Logger cfg *Config bucket *storage.BucketHandle hedgedBucket *storage.BucketHandle @@ -103,7 +100,6 @@ func internalNew(cfg *Config, confirm bool) (*readerWriter, error) { } rw := &readerWriter{ - logger: log.Logger, cfg: cfg, bucket: bucket, hedgedBucket: hedgedBucket, diff --git a/tempodb/backend/local/compactor.go b/tempodb/backend/local/compactor.go index a0de3128d9a..eed15c7bbd0 100644 --- a/tempodb/backend/local/compactor.go +++ b/tempodb/backend/local/compactor.go @@ -7,21 +7,11 @@ import ( "os" "path" - "github.com/go-kit/log/level" "github.com/google/uuid" - "github.com/grafana/tempo/pkg/util/log" "github.com/grafana/tempo/tempodb/backend" ) func (rw *Backend) MarkBlockCompacted(blockID uuid.UUID, tenantID string) error { - metaFilenamePb := rw.metaFileNamePb(blockID, tenantID) - compactedMetaFilenamePb := rw.compactedMetaFileNamePb(blockID, tenantID) - - err := os.Rename(metaFilenamePb, compactedMetaFilenamePb) - if err != nil { - level.Error(log.Logger).Log("msg", "error copying obj meta.pb to compacted.pb, is this block from previous Tempo version?", "err", err) - } - // move meta file to a new location metaFilename := rw.metaFileName(blockID, tenantID) compactedMetaFilename := rw.compactedMetaFileName(blockID, tenantID) @@ -48,13 +38,6 @@ func (rw *Backend) ClearBlock(blockID uuid.UUID, tenantID string) error { } func (rw *Backend) CompactedBlockMeta(blockID uuid.UUID, tenantID string) (*backend.CompactedBlockMeta, error) { - outPb, err := rw.compactedBlockMetaPb(blockID, tenantID) - if err == nil { - return outPb, nil - } - - // TODO: record a note about fallback - filename := rw.compactedMetaFileName(blockID, tenantID) fi, err := os.Stat(filename) @@ -77,32 +60,6 @@ func (rw *Backend) CompactedBlockMeta(blockID uuid.UUID, tenantID string) (*back return out, nil } -func (rw *Backend) compactedBlockMetaPb(blockID uuid.UUID, tenantID string) (*backend.CompactedBlockMeta, error) { - filename := rw.compactedMetaFileNamePb(blockID, tenantID) - fi, err := os.Stat(filename) - if err != nil { - return nil, readError(err) - } - - bytes, err := os.ReadFile(filename) - if err != nil { - return nil, readError(err) - } - - out := &backend.CompactedBlockMeta{} - err = out.Unmarshal(bytes) - if err != nil { - return nil, err - } - out.CompactedTime = fi.ModTime() - - return out, nil -} - func (rw *Backend) compactedMetaFileName(blockID uuid.UUID, tenantID string) string { return path.Join(rw.rootPath(backend.KeyPathForBlock(blockID, tenantID)), backend.CompactedMetaName) } - -func (rw *Backend) compactedMetaFileNamePb(blockID uuid.UUID, tenantID string) string { - return path.Join(rw.rootPath(backend.KeyPathForBlock(blockID, tenantID)), backend.CompactedMetaNamePb) -} diff --git a/tempodb/backend/local/local.go b/tempodb/backend/local/local.go index 1c6c2e1a795..b75edd585f1 100644 --- a/tempodb/backend/local/local.go +++ b/tempodb/backend/local/local.go @@ -307,10 +307,6 @@ func (rw *Backend) metaFileName(blockID uuid.UUID, tenantID string) string { return filepath.Join(rw.rootPath(backend.KeyPathForBlock(blockID, tenantID)), backend.MetaName) } -func (rw *Backend) metaFileNamePb(blockID uuid.UUID, tenantID string) string { - return filepath.Join(rw.rootPath(backend.KeyPathForBlock(blockID, tenantID)), backend.MetaNamePb) -} - func (rw *Backend) rootPath(keypath backend.KeyPath) string { return filepath.Join(rw.cfg.Path, filepath.Join(keypath...)) } diff --git a/tempodb/backend/mocks.go b/tempodb/backend/mocks.go index 5b747fe6412..bfe02bfa5cc 100644 --- a/tempodb/backend/mocks.go +++ b/tempodb/backend/mocks.go @@ -72,7 +72,7 @@ func (m *MockRawReader) Shutdown() {} // MockRawWriter type MockRawWriter struct { - writeBuffer [][]byte + writeBuffer []byte appendBuffer []byte closeAppendCalled bool deleteCalls map[string]map[string]int @@ -81,11 +81,11 @@ type MockRawWriter struct { func (m *MockRawWriter) Write(_ context.Context, _ string, _ KeyPath, data io.Reader, size int64, _ *CacheInfo) error { if m.writeBuffer == nil { - m.writeBuffer = make([][]byte, 0) + m.writeBuffer = make([]byte, 0) } writeBuffer, err := tempo_io.ReadAllWithEstimate(data, size) - m.writeBuffer = append(m.writeBuffer, writeBuffer) + m.writeBuffer = writeBuffer return err } diff --git a/tempodb/backend/raw.go b/tempodb/backend/raw.go index 1e0540dc3e5..96399e9c3d1 100644 --- a/tempodb/backend/raw.go +++ b/tempodb/backend/raw.go @@ -9,7 +9,6 @@ import ( "path" "time" - proto "github.com/gogo/protobuf/proto" "github.com/google/uuid" tempo_io "github.com/grafana/tempo/pkg/io" @@ -22,9 +21,7 @@ const ( TenantIndexName = "index.json.gz" // Proto - MetaNamePb = "meta.pb" - CompactedMetaNamePb = "meta.compacted.pb" - TenantIndexNamePb = "index.pb" + TenantIndexNamePb = "index.pb" // File name for the cluster seed file. ClusterSeedFileName = "tempo_cluster_seed.json" @@ -107,18 +104,6 @@ func (w *writer) WriteBlockMeta(ctx context.Context, meta *BlockMeta) error { tenantID = meta.TenantID ) - // marshal and write proto to the backend - mPb, err := proto.Marshal(meta) - if err != nil { - return err - } - - err = w.w.Write(ctx, MetaNamePb, KeyPathForBlock((uuid.UUID)(blockID), tenantID), bytes.NewReader(mPb), int64(len(mPb)), nil) - if err != nil { - return err - } - - // marshal and write json to the backend bMeta, err := json.Marshal(meta) if err != nil { return err @@ -157,22 +142,12 @@ func (w *writer) WriteTenantIndex(ctx context.Context, tenantID string, meta []* b := newTenantIndex(meta, compactedMeta) - indexBytesPb, err := proto.Marshal(b) - if err != nil { - return err - } - - err = w.w.Write(ctx, TenantIndexNamePb, KeyPath([]string{tenantID}), bytes.NewReader(indexBytesPb), int64(len(indexBytesPb)), nil) - if err != nil { - return err - } - - indexBytes, err := b.marshal() + indexBytesPb, err := b.marshalPb() if err != nil { return err } - return w.w.Write(ctx, TenantIndexName, KeyPath([]string{tenantID}), bytes.NewReader(indexBytes), int64(len(indexBytes)), nil) + return w.w.Write(ctx, TenantIndexNamePb, KeyPath([]string{tenantID}), bytes.NewReader(indexBytesPb), int64(len(indexBytesPb)), nil) } // Delete implements backend.Writer @@ -233,16 +208,6 @@ func (r *reader) Blocks(ctx context.Context, tenantID string) ([]uuid.UUID, []uu // BlockMeta implements backend.Reader func (r *reader) BlockMeta(ctx context.Context, blockID uuid.UUID, tenantID string) (*BlockMeta, error) { - ctx, span := tracer.Start(ctx, "reader.BlockMeta") - defer span.End() - - outPb, err := r.blockMetaPb(ctx, blockID, tenantID) - if err == nil { - return outPb, nil - } - - span.AddEvent(EventJSONFallback) - reader, size, err := r.r.Read(ctx, MetaName, KeyPathForBlock(blockID, tenantID), nil) if err != nil { return nil, err @@ -263,28 +228,6 @@ func (r *reader) BlockMeta(ctx context.Context, blockID uuid.UUID, tenantID stri return out, nil } -func (r *reader) blockMetaPb(ctx context.Context, blockID uuid.UUID, tenantID string) (*BlockMeta, error) { - // Read proto first, and fall back to json - readerPb, size, err := r.r.Read(ctx, MetaNamePb, KeyPathForBlock(blockID, tenantID), nil) - if err != nil { - return nil, err - } - defer readerPb.Close() - - bytesPb, err := tempo_io.ReadAllWithEstimate(readerPb, size) - if err != nil { - return nil, err - } - - outPb := &BlockMeta{} - err = outPb.Unmarshal(bytesPb) - if err != nil { - return nil, err - } - - return outPb, nil -} - // TenantIndex implements backend.Reader func (r *reader) TenantIndex(ctx context.Context, tenantID string) (*TenantIndex, error) { ctx, span := tracer.Start(ctx, "reader.TenantIndex") @@ -330,7 +273,7 @@ func (r *reader) tenantIndexProto(ctx context.Context, tenantID string) (*Tenant } out := &TenantIndex{} - err = out.Unmarshal(bytesPb) + err = out.unmarshalPb(bytesPb) if err != nil { return nil, err } @@ -372,19 +315,11 @@ func MetaFileName(blockID uuid.UUID, tenantID, prefix string) string { return path.Join(prefix, tenantID, blockID.String(), MetaName) } -func MetaFileNamePb(blockID uuid.UUID, tenantID, prefix string) string { - return path.Join(prefix, tenantID, blockID.String(), MetaNamePb) -} - // CompactedMetaFileName returns the object name for the compacted block meta given a block id and tenantid func CompactedMetaFileName(blockID uuid.UUID, tenantID, prefix string) string { return path.Join(prefix, tenantID, blockID.String(), CompactedMetaName) } -func CompactedMetaFileNamePb(blockID uuid.UUID, tenantID, prefix string) string { - return path.Join(prefix, tenantID, blockID.String(), CompactedMetaNamePb) -} - // RootPath returns the root path for a block given a block id and tenantid func RootPath(blockID uuid.UUID, tenantID, prefix string) string { return path.Join(prefix, tenantID, blockID.String()) diff --git a/tempodb/backend/raw_test.go b/tempodb/backend/raw_test.go index fc6763b54b1..d843d12a30e 100644 --- a/tempodb/backend/raw_test.go +++ b/tempodb/backend/raw_test.go @@ -5,7 +5,6 @@ import ( "encoding/json" "testing" - proto "github.com/gogo/protobuf/proto" "github.com/google/go-cmp/cmp" "github.com/google/uuid" "github.com/stretchr/testify/assert" @@ -26,7 +25,7 @@ func TestWriter(t *testing.T) { err := w.Write(ctx, "test", uuid.New(), "test", expected, nil) assert.NoError(t, err) - assert.Equal(t, expected, m.writeBuffer[len(m.writeBuffer)-1]) + assert.Equal(t, expected, m.writeBuffer) _, err = w.Append(ctx, "test", uuid.New(), "test", nil, expected) assert.NoError(t, err) @@ -37,54 +36,23 @@ func TestWriter(t *testing.T) { assert.True(t, m.closeAppendCalled) meta := NewBlockMeta("test", uuid.New(), "blerg", EncGZIP, "glarg") - - // RoundTrip with empty DedicatedColumns - expectedPb, err := meta.Marshal() - assert.NoError(t, err) - expectedPb2 := &BlockMeta{} - err = expectedPb2.Unmarshal(expectedPb) - assert.NoError(t, err) - assert.Equal(t, meta, expectedPb2) - - // RoundTrip with non-empty DedicatedColumns - meta.DedicatedColumns = DedicatedColumns{ - {Scope: "resource", Name: "namespace", Type: "string"}, - {Scope: "span", Name: "http.method", Type: "string"}, - {Scope: "span", Name: "namespace", Type: "string"}, - } - - expectedPb, err = meta.Marshal() - assert.NoError(t, err) - expectedPb3 := &BlockMeta{} - err = expectedPb3.Unmarshal(expectedPb) + jsonBytes, err := json.Marshal(meta) assert.NoError(t, err) - assert.Equal(t, meta, expectedPb3) - - // Round trip the json - expected, err = json.Marshal(meta) - assert.NoError(t, err) - expected2 := &BlockMeta{} - err = json.Unmarshal(expected, expected2) - assert.NoError(t, err) - assert.Equal(t, meta, expected2) // Write the block meta to the backend and validate the payloads. err = w.WriteBlockMeta(ctx, meta) assert.NoError(t, err) - assert.Equal(t, expectedPb, m.writeBuffer[len(m.writeBuffer)-2]) - assert.Equal(t, expected, m.writeBuffer[len(m.writeBuffer)-1]) + assert.Equal(t, jsonBytes, m.writeBuffer) // Write the tenant index to the backend and validate the payloads. err = w.WriteTenantIndex(ctx, "test", []*BlockMeta{meta}, nil) assert.NoError(t, err) - idxPb := &TenantIndex{} - err = proto.Unmarshal(m.writeBuffer[len(m.writeBuffer)-2], idxPb) - assert.NoError(t, err) idx := &TenantIndex{} - err = idx.unmarshal(m.writeBuffer[len(m.writeBuffer)-1]) + err = idx.unmarshalPb(m.writeBuffer) assert.NoError(t, err) + assert.Equal(t, []*BlockMeta{meta}, idx.Meta) assert.True(t, cmp.Equal([]*BlockMeta{meta}, idx.Meta)) // using cmp.Equal to compare json datetimes assert.True(t, cmp.Equal([]*CompactedBlockMeta(nil), idx.CompactedMeta)) // using cmp.Equal to compare json datetimes @@ -217,3 +185,40 @@ func TestRootPath(t *testing.T) { assert.Equal(t, prefix+"/"+tid+"/"+b.String(), rootPath) } + +func TestRoundTripMeta(t *testing.T) { + // RoundTrip with empty DedicatedColumns + meta := NewBlockMeta("test", uuid.New(), "blerg", EncGZIP, "glarg") + // RoundTrip with empty DedicatedColumns + expectedPb, err := meta.Marshal() + assert.NoError(t, err) + expectedPb2 := &BlockMeta{} + err = expectedPb2.Unmarshal(expectedPb) + assert.NoError(t, err) + assert.Equal(t, meta, expectedPb2) + + // RoundTrip with non-empty DedicatedColumns + meta.DedicatedColumns = DedicatedColumns{ + {Scope: "resource", Name: "namespace", Type: "string"}, + {Scope: "span", Name: "http.method", Type: "string"}, + {Scope: "span", Name: "namespace", Type: "string"}, + } + + expectedPb, err = meta.Marshal() + assert.NoError(t, err) + expectedPb3 := &BlockMeta{} + err = expectedPb3.Unmarshal(expectedPb) + assert.NoError(t, err) + assert.Equal(t, meta, expectedPb3) + + // Round trip the json + jsonBytes, err := json.Marshal(meta) + assert.NoError(t, err) + expected2 := &BlockMeta{} + err = json.Unmarshal(jsonBytes, expected2) + assert.NoError(t, err) + assert.Equal(t, meta, expected2) + + // Does json have the same object as proto? + assert.Equal(t, meta, expected2, expectedPb2, expectedPb3) +} diff --git a/tempodb/backend/s3/compactor.go b/tempodb/backend/s3/compactor.go index 12793b1c61d..21fa37fc323 100644 --- a/tempodb/backend/s3/compactor.go +++ b/tempodb/backend/s3/compactor.go @@ -21,33 +21,11 @@ func (rw *readerWriter) MarkBlockCompacted(blockID uuid.UUID, tenantID string) e } putObjectOptions := getPutObjectOptions(rw) - ctx := context.TODO() - - metaFileNamePb := backend.MetaFileNamePb(blockID, tenantID, rw.cfg.Prefix) - // copy meta.json to meta.compacted.json - _, err := rw.core.CopyObject( - ctx, - rw.cfg.Bucket, - metaFileNamePb, - rw.cfg.Bucket, - backend.CompactedMetaFileNamePb(blockID, tenantID, rw.cfg.Prefix), - nil, - minio.CopySrcOptions{}, - putObjectOptions, - ) - if err != nil { - level.Error(rw.logger).Log("msg", "error copying obj meta.pb to compacted.pb, is this block from previous Tempo version?", "err", err) - } else { - err = rw.core.RemoveObject(ctx, rw.cfg.Bucket, metaFileNamePb, minio.RemoveObjectOptions{}) - if err != nil { - return err - } - } metaFileName := backend.MetaFileName(blockID, tenantID, rw.cfg.Prefix) // copy meta.json to meta.compacted.json - _, err = rw.core.CopyObject( - ctx, + _, err := rw.core.CopyObject( + context.TODO(), rw.cfg.Bucket, metaFileName, rw.cfg.Bucket, @@ -61,7 +39,7 @@ func (rw *readerWriter) MarkBlockCompacted(blockID uuid.UUID, tenantID string) e } // delete meta.json - return rw.core.RemoveObject(ctx, rw.cfg.Bucket, metaFileName, minio.RemoveObjectOptions{}) + return rw.core.RemoveObject(context.TODO(), rw.cfg.Bucket, metaFileName, minio.RemoveObjectOptions{}) } func (rw *readerWriter) ClearBlock(blockID uuid.UUID, tenantID string) error { @@ -100,13 +78,6 @@ func (rw *readerWriter) CompactedBlockMeta(blockID uuid.UUID, tenantID string) ( return nil, backend.ErrEmptyBlockID } - outPb, err := rw.compactedBlockMetaPb(blockID, tenantID) - if err == nil { - return outPb, nil - } - - // TODO: record a note about fallback - compactedMetaFileName := backend.CompactedMetaFileName(blockID, tenantID, rw.cfg.Prefix) bytes, info, err := rw.readAllWithObjInfo(context.TODO(), compactedMetaFileName) if err != nil { @@ -122,20 +93,3 @@ func (rw *readerWriter) CompactedBlockMeta(blockID uuid.UUID, tenantID string) ( return out, nil } - -func (rw *readerWriter) compactedBlockMetaPb(blockID uuid.UUID, tenantID string) (*backend.CompactedBlockMeta, error) { - compactedMetaFileNamePb := backend.CompactedMetaFileNamePb(blockID, tenantID, rw.cfg.Prefix) - bytes, info, err := rw.readAllWithObjInfo(context.TODO(), compactedMetaFileNamePb) - if err != nil { - return nil, readError(err) - } - - out := &backend.CompactedBlockMeta{} - err = out.Unmarshal(bytes) - if err != nil { - return nil, err - } - out.CompactedTime = info.LastModified - - return out, nil -} diff --git a/tempodb/backend/s3/s3.go b/tempodb/backend/s3/s3.go index 31a78304f66..c434de1339f 100644 --- a/tempodb/backend/s3/s3.go +++ b/tempodb/backend/s3/s3.go @@ -103,6 +103,8 @@ func internalNew(cfg *Config, confirm bool) (*readerWriter, error) { return nil, fmt.Errorf("config is nil") } + l := log.Logger + core, err := createCore(cfg, false) if err != nil { return nil, fmt.Errorf("unexpected error creating core: %w", err) @@ -122,7 +124,7 @@ func internalNew(cfg *Config, confirm bool) (*readerWriter, error) { } rw := &readerWriter{ - logger: log.Logger, + logger: l, cfg: cfg, core: core, hedgedCore: hedgedCore, diff --git a/tempodb/backend/tenantindex.go b/tempodb/backend/tenantindex.go index 2466bfb72f9..fc32f5aee11 100644 --- a/tempodb/backend/tenantindex.go +++ b/tempodb/backend/tenantindex.go @@ -59,3 +59,11 @@ func (b *TenantIndex) unmarshal(buffer []byte) error { d := json.NewDecoder(gzipReader) return d.Decode(b) } + +func (b *TenantIndex) marshalPb() ([]byte, error) { + return proto.Marshal(b) +} + +func (b *TenantIndex) unmarshalPb(buffer []byte) error { + return b.Unmarshal(buffer) +} From 759b248500b0bc4d512ab9d4f3fac78c81fdd5e4 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Tue, 24 Sep 2024 18:47:38 +0000 Subject: [PATCH 46/71] Drop additional proto include --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 38683be310b..45f4ae59c6d 100644 --- a/Makefile +++ b/Makefile @@ -222,7 +222,7 @@ PROTOC = docker run --rm -u ${shell id -u} -v${PWD}:${PWD} -w${PWD} ${DOCKER_PRO PROTO_INTERMEDIATE_DIR = pkg/.patched-proto PROTO_INCLUDES = -I$(PROTO_INTERMEDIATE_DIR) PROTO_GEN = $(PROTOC) $(PROTO_INCLUDES) --gogofaster_out=plugins=grpc,paths=source_relative:$(2) $(1) -PROTO_GEN_WITH_VENDOR = $(PROTOC) $(PROTO_INCLUDES) -Ivendor -Ivendor/github.com/gogo/protobuf -Ipkg/tempopb --gogofaster_out=plugins=grpc,paths=source_relative:$(2) $(1) +PROTO_GEN_WITH_VENDOR = $(PROTOC) $(PROTO_INCLUDES) -Ivendor -Ivendor/github.com/gogo/protobuf --gogofaster_out=plugins=grpc,paths=source_relative:$(2) $(1) PROTO_GEN_WITHOUT_RELATIVE = $(PROTOC) $(PROTO_INCLUDES) --gogofaster_out=plugins=grpc:$(2) $(1) .PHONY: gen-proto From d167ee311dcad581b8bdff9942df49304f023f51 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Tue, 24 Sep 2024 19:15:16 +0000 Subject: [PATCH 47/71] Implement zstd tenant index compression --- tempodb/backend/raw.go | 2 +- tempodb/backend/tenantindex.go | 37 ++++++++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/tempodb/backend/raw.go b/tempodb/backend/raw.go index 96399e9c3d1..5fef93b99c3 100644 --- a/tempodb/backend/raw.go +++ b/tempodb/backend/raw.go @@ -21,7 +21,7 @@ const ( TenantIndexName = "index.json.gz" // Proto - TenantIndexNamePb = "index.pb" + TenantIndexNamePb = "index.pb.zst" // File name for the cluster seed file. ClusterSeedFileName = "tempo_cluster_seed.json" diff --git a/tempodb/backend/tenantindex.go b/tempodb/backend/tenantindex.go index fc32f5aee11..1ea5f35bc97 100644 --- a/tempodb/backend/tenantindex.go +++ b/tempodb/backend/tenantindex.go @@ -7,6 +7,7 @@ import ( proto "github.com/gogo/protobuf/proto" "github.com/klauspost/compress/gzip" + "github.com/klauspost/compress/zstd" ) const ( @@ -61,9 +62,41 @@ func (b *TenantIndex) unmarshal(buffer []byte) error { } func (b *TenantIndex) marshalPb() ([]byte, error) { - return proto.Marshal(b) + buffer := &bytes.Buffer{} + + z, err := zstd.NewWriter(buffer) + if err != nil { + return nil, err + } + + pbBytes, err := proto.Marshal(b) + if err != nil { + return nil, err + } + + if _, err = z.Write(pbBytes); err != nil { + return nil, err + } + if err = z.Flush(); err != nil { + return nil, err + } + if err = z.Close(); err != nil { + return nil, err + } + + return buffer.Bytes(), nil } func (b *TenantIndex) unmarshalPb(buffer []byte) error { - return b.Unmarshal(buffer) + decoder, err := zstd.NewReader(nil, zstd.WithDecoderConcurrency(0)) + if err != nil { + return err + } + + bb, err := decoder.DecodeAll(buffer, nil) + if err != nil { + return err + } + + return b.Unmarshal(bb) } From 1509b5ba9e9db501dd31610c9407dc5b6a43992f Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Tue, 24 Sep 2024 19:23:29 +0000 Subject: [PATCH 48/71] Add note about use of json in the dedicatedcolumns --- tempodb/backend/block_meta.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tempodb/backend/block_meta.go b/tempodb/backend/block_meta.go index 78d249aa88e..f8b0a6e9638 100644 --- a/tempodb/backend/block_meta.go +++ b/tempodb/backend/block_meta.go @@ -309,6 +309,8 @@ func (dcs DedicatedColumns) Marshal() ([]byte, error) { return nil, nil } + // NOTE: This is a performance optimization to avoid re-unmarshalling the + // same data multiple times on the read. return json.Marshal(dcs) } @@ -327,6 +329,8 @@ func (dcs *DedicatedColumns) Unmarshal(data []byte) error { return nil } + // NOTE: See UnmarshalJSON for a performance optomization to record the json + // bytes for reuse. return json.Unmarshal(data, &dcs) } From b814d829667267e27f13afd876dc77b898bce91b Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Tue, 24 Sep 2024 19:45:31 +0000 Subject: [PATCH 49/71] Fix ingester local block --- modules/ingester/local_block.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ingester/local_block.go b/modules/ingester/local_block.go index 62497865288..05bd3ffe6cf 100644 --- a/modules/ingester/local_block.go +++ b/modules/ingester/local_block.go @@ -128,11 +128,11 @@ func (c *LocalBlock) Write(ctx context.Context, w backend.Writer) error { } func (c *LocalBlock) SetDiskCache(ctx context.Context, cacheKey string, data []byte) error { - return c.writer.Write(ctx, cacheKey, c.BlockMeta().BlockID, c.BlockMeta().TenantID, data, nil) + return c.writer.Write(ctx, cacheKey, (uuid.UUID)(c.BlockMeta().BlockID), c.BlockMeta().TenantID, data, nil) } func (c *LocalBlock) GetDiskCache(ctx context.Context, cacheKey string) ([]byte, error) { - data, err := c.reader.Read(ctx, cacheKey, c.BlockMeta().BlockID, c.BlockMeta().TenantID, nil) + data, err := c.reader.Read(ctx, cacheKey, (uuid.UUID)(c.BlockMeta().BlockID), c.BlockMeta().TenantID, nil) if errors.Is(err, backend.ErrDoesNotExist) { // file doesn't exist, so it's a cache miss return nil, nil From 5921ee92a0ac87ba936aff1c6a05d0f5ef3574c8 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 25 Sep 2024 13:25:17 +0000 Subject: [PATCH 50/71] Spell --- tempodb/backend/block_meta.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tempodb/backend/block_meta.go b/tempodb/backend/block_meta.go index f8b0a6e9638..b0aa59f8717 100644 --- a/tempodb/backend/block_meta.go +++ b/tempodb/backend/block_meta.go @@ -329,7 +329,7 @@ func (dcs *DedicatedColumns) Unmarshal(data []byte) error { return nil } - // NOTE: See UnmarshalJSON for a performance optomization to record the json + // NOTE: See UnmarshalJSON for a performance optimization to record the json // bytes for reuse. return json.Unmarshal(data, &dcs) } From b137f145c00b598bab03bd499ae7f11240bf11e3 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 25 Sep 2024 14:08:39 +0000 Subject: [PATCH 51/71] Revert mock update --- tempodb/backend/mocks.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tempodb/backend/mocks.go b/tempodb/backend/mocks.go index bfe02bfa5cc..15f5dcbc836 100644 --- a/tempodb/backend/mocks.go +++ b/tempodb/backend/mocks.go @@ -80,13 +80,8 @@ type MockRawWriter struct { } func (m *MockRawWriter) Write(_ context.Context, _ string, _ KeyPath, data io.Reader, size int64, _ *CacheInfo) error { - if m.writeBuffer == nil { - m.writeBuffer = make([]byte, 0) - } - - writeBuffer, err := tempo_io.ReadAllWithEstimate(data, size) - m.writeBuffer = writeBuffer - + var err error + m.writeBuffer, err = tempo_io.ReadAllWithEstimate(data, size) return err } From 705d9bbfbeca45de0f7798892b8171f617de3500 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 25 Sep 2024 14:12:44 +0000 Subject: [PATCH 52/71] Drop json fallback from tenantindex read --- tempodb/backend/backend.go | 4 ---- tempodb/backend/raw.go | 29 +---------------------------- 2 files changed, 1 insertion(+), 32 deletions(-) diff --git a/tempodb/backend/backend.go b/tempodb/backend/backend.go index 93a1f006d47..c3a49444b6f 100644 --- a/tempodb/backend/backend.go +++ b/tempodb/backend/backend.go @@ -6,7 +6,6 @@ import ( "io" "github.com/google/uuid" - "go.opentelemetry.io/otel" "github.com/grafana/tempo/pkg/cache" ) @@ -25,9 +24,6 @@ var ( ErrBadSeedFile = fmt.Errorf("bad seed file") GlobalMaxBlockID = uuid.MustParse("ffffffff-ffff-ffff-ffff-ffffffffffff") - - tracer = otel.Tracer("backend") - EventJSONFallback = "falling back to json" ) type CacheInfo struct { diff --git a/tempodb/backend/raw.go b/tempodb/backend/raw.go index 5fef93b99c3..85e96ca0c33 100644 --- a/tempodb/backend/raw.go +++ b/tempodb/backend/raw.go @@ -230,34 +230,7 @@ func (r *reader) BlockMeta(ctx context.Context, blockID uuid.UUID, tenantID stri // TenantIndex implements backend.Reader func (r *reader) TenantIndex(ctx context.Context, tenantID string) (*TenantIndex, error) { - ctx, span := tracer.Start(ctx, "reader.TenantIndex") - defer span.End() - - outPb, err := r.tenantIndexProto(ctx, tenantID) - if err == nil { - return outPb, nil - } - - span.AddEvent(EventJSONFallback) - - readerJ, size, err := r.r.Read(ctx, TenantIndexName, KeyPath([]string{tenantID}), nil) - if err != nil { - return nil, err - } - defer readerJ.Close() - - bytesJ, err := tempo_io.ReadAllWithEstimate(readerJ, size) - if err != nil { - return nil, err - } - - i := &TenantIndex{} - err = i.unmarshal(bytesJ) - if err != nil { - return nil, err - } - - return i, nil + return r.tenantIndexProto(ctx, tenantID) } func (r *reader) tenantIndexProto(ctx context.Context, tenantID string) (*TenantIndex, error) { From 823d2b7179036830e6fdada010e3af8015bc04e7 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 25 Sep 2024 14:18:41 +0000 Subject: [PATCH 53/71] Replace single-tenant test fixtures --- .../meta.compacted.pb | Bin 75 -> 0 bytes .../meta.json | 2 +- .../meta.json | 2 +- .../9a5dbb1c-f2bc-4414-aae2-1e7a16b4a06c/meta.pb | Bin 75 -> 0 bytes .../abda0e34-63a1-4379-8c40-8ad6bac8cb85/meta.pb | Bin 75 -> 0 bytes .../cfc82d55-7c16-4dfc-a298-e514224b7e19/meta.pb | Bin 75 -> 0 bytes .../meta.json | 2 +- .../meta.compacted.json | 2 +- .../test/test-data/single-tenant/index.json.gz | Bin 409 -> 0 bytes .../backend/test/test-data/single-tenant/index.pb | Bin 338 -> 0 bytes .../test/test-data/single-tenant/index.pb.zst | Bin 0 -> 193 bytes 11 files changed, 4 insertions(+), 4 deletions(-) delete mode 100644 tempodb/backend/test/test-data/single-tenant/66610181-fb0d-4b4c-be2f-cea4a87f4c86/meta.compacted.pb rename tempodb/backend/test/test-data/single-tenant/{abda0e34-63a1-4379-8c40-8ad6bac8cb85 => 709f51b4-4e04-464a-89e0-f1f8d956e633}/meta.json (78%) rename tempodb/backend/test/test-data/single-tenant/{cfc82d55-7c16-4dfc-a298-e514224b7e19 => 8ff0b000-3138-4665-84bf-630caff577a5}/meta.json (78%) delete mode 100644 tempodb/backend/test/test-data/single-tenant/9a5dbb1c-f2bc-4414-aae2-1e7a16b4a06c/meta.pb delete mode 100644 tempodb/backend/test/test-data/single-tenant/abda0e34-63a1-4379-8c40-8ad6bac8cb85/meta.pb delete mode 100644 tempodb/backend/test/test-data/single-tenant/cfc82d55-7c16-4dfc-a298-e514224b7e19/meta.pb rename tempodb/backend/test/test-data/single-tenant/{9a5dbb1c-f2bc-4414-aae2-1e7a16b4a06c => f5ac87ed-77f1-408e-9c98-785692900e81}/meta.json (78%) rename tempodb/backend/test/test-data/single-tenant/{66610181-fb0d-4b4c-be2f-cea4a87f4c86 => fa599055-6305-43a9-9a17-5ff9b208cd01}/meta.compacted.json (78%) delete mode 100644 tempodb/backend/test/test-data/single-tenant/index.json.gz delete mode 100644 tempodb/backend/test/test-data/single-tenant/index.pb create mode 100644 tempodb/backend/test/test-data/single-tenant/index.pb.zst diff --git a/tempodb/backend/test/test-data/single-tenant/66610181-fb0d-4b4c-be2f-cea4a87f4c86/meta.compacted.pb b/tempodb/backend/test/test-data/single-tenant/66610181-fb0d-4b4c-be2f-cea4a87f4c86/meta.compacted.pb deleted file mode 100644 index 776259e45edf13ed156f0f9c6acc9c4190dd923e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 75 zcmd;LDl-%kNK0gF{LSm_vrqrrk`?tnZCbp=nR)3ssk$Ypd5L)?M%)|?lXe`Q@$dit V|BP11oG3=6^s3APrL-P diff --git a/tempodb/backend/test/test-data/single-tenant/abda0e34-63a1-4379-8c40-8ad6bac8cb85/meta.json b/tempodb/backend/test/test-data/single-tenant/709f51b4-4e04-464a-89e0-f1f8d956e633/meta.json similarity index 78% rename from tempodb/backend/test/test-data/single-tenant/abda0e34-63a1-4379-8c40-8ad6bac8cb85/meta.json rename to tempodb/backend/test/test-data/single-tenant/709f51b4-4e04-464a-89e0-f1f8d956e633/meta.json index ccdc2089355..110216ceade 100644 --- a/tempodb/backend/test/test-data/single-tenant/abda0e34-63a1-4379-8c40-8ad6bac8cb85/meta.json +++ b/tempodb/backend/test/test-data/single-tenant/709f51b4-4e04-464a-89e0-f1f8d956e633/meta.json @@ -1 +1 @@ -{"format":"v3","blockID":"abda0e34-63a1-4379-8c40-8ad6bac8cb85","tenantID":"single-tenant","startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z","totalObjects":0,"compactionLevel":0,"encoding":"lz4","indexPageSize":0,"totalRecords":0,"dataEncoding":"adsf","bloomShards":0,"footerSize":0} \ No newline at end of file +{"format":"v3","blockID":"709f51b4-4e04-464a-89e0-f1f8d956e633","tenantID":"single-tenant","startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z","totalObjects":0,"compactionLevel":0,"encoding":"lz4","indexPageSize":0,"totalRecords":0,"dataEncoding":"adsf","bloomShards":0,"footerSize":0} \ No newline at end of file diff --git a/tempodb/backend/test/test-data/single-tenant/cfc82d55-7c16-4dfc-a298-e514224b7e19/meta.json b/tempodb/backend/test/test-data/single-tenant/8ff0b000-3138-4665-84bf-630caff577a5/meta.json similarity index 78% rename from tempodb/backend/test/test-data/single-tenant/cfc82d55-7c16-4dfc-a298-e514224b7e19/meta.json rename to tempodb/backend/test/test-data/single-tenant/8ff0b000-3138-4665-84bf-630caff577a5/meta.json index 868f799643c..a9dbce97115 100644 --- a/tempodb/backend/test/test-data/single-tenant/cfc82d55-7c16-4dfc-a298-e514224b7e19/meta.json +++ b/tempodb/backend/test/test-data/single-tenant/8ff0b000-3138-4665-84bf-630caff577a5/meta.json @@ -1 +1 @@ -{"format":"v4","blockID":"cfc82d55-7c16-4dfc-a298-e514224b7e19","tenantID":"single-tenant","startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z","totalObjects":0,"compactionLevel":0,"encoding":"lz4-1M","indexPageSize":0,"totalRecords":0,"dataEncoding":"adsf","bloomShards":0,"footerSize":0} \ No newline at end of file +{"format":"v4","blockID":"8ff0b000-3138-4665-84bf-630caff577a5","tenantID":"single-tenant","startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z","totalObjects":0,"compactionLevel":0,"encoding":"lz4-1M","indexPageSize":0,"totalRecords":0,"dataEncoding":"adsf","bloomShards":0,"footerSize":0} \ No newline at end of file diff --git a/tempodb/backend/test/test-data/single-tenant/9a5dbb1c-f2bc-4414-aae2-1e7a16b4a06c/meta.pb b/tempodb/backend/test/test-data/single-tenant/9a5dbb1c-f2bc-4414-aae2-1e7a16b4a06c/meta.pb deleted file mode 100644 index 910770514b4da856de0cff5181f6562302d31847..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 75 zcmd;LDl-xim=(KQ=F=V*kyVf6s>HS|$kF00&df{CN!2Y$%}dNHG2-TEn6%^YjDP?C W|7Wy9=0q_n<>lw4Dy4NXG5`RQJs>Fn diff --git a/tempodb/backend/test/test-data/single-tenant/abda0e34-63a1-4379-8c40-8ad6bac8cb85/meta.pb b/tempodb/backend/test/test-data/single-tenant/abda0e34-63a1-4379-8c40-8ad6bac8cb85/meta.pb deleted file mode 100644 index 663409beb1ce820ba1c39e310ae76f22f8609f50..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 75 zcmd;LDl--mSbdAnBzd88WsgJGwOuDpw`%bgXXd5nr0SNW<|XEp7;$qnOxkgH#=rmn V|1(-4bD|iPa;i*}iqpCn8345xAie+q diff --git a/tempodb/backend/test/test-data/single-tenant/cfc82d55-7c16-4dfc-a298-e514224b7e19/meta.pb b/tempodb/backend/test/test-data/single-tenant/cfc82d55-7c16-4dfc-a298-e514224b7e19/meta.pb deleted file mode 100644 index e78db268d304652dfa7aca8187c1f5df093fe031..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 75 zcmd;LDl-uhIDbMnv_{PL&!QPmMU=ejB(->pGxO4OQgusG^Aht)jJP=(Cha&pfo!kUH2#Vs) zX=Rb>>dF|MbT64^ky+-y%Vt*HfyLX(K%I*B9x(8X5i^kUl25`m^njUSvvE5MD zL*ricwKYv`y}yPEW-ScEmwOoVGV_Dw&OrrXm*vO1H!wiYO$@;bjxGoiSwd!YXtiV8 z24d3+R8TZ=Dyw5ZrR`4fw1Eotg_p9KW`zNaF&5X^7&EN%&_YxEx1i+0yN}_!O4-9; zDv&(ivXm*O_j;$hb*D*koYEEsNI5A~Fr}zJKk-(trh~4UHR!WSUg9Yza^bgsjU4ym z>HT@W`o_OiW6njF$CP9B6jyzQi$i3iHDOz`MXI|Vy^ulAu?;LiO@p1-7AcN`?0S#dSaOa+r?$UHT4+DK9I%@|4K#jz=7ZWZhHcwgW4*;On1~ce zFsK_*l!<*elKA%W7;X>K?TZn7!tb&5vv<&Sou`JHYdGEGj0|AIjD-YN-{Lb#Ug%ueAt{KZ|BO6;bl8lO)kFT|-|bMh2;9E|5nJg#^+P k85@7|di(6tKeuE>y-yn{#-&$f7C<}-3&V$dHt%8v04+INw+0Z0*ZoowO9}#ZGZGMRpHZ|<1V&1U;PLp` zR^~G*4RdL3XKZCHbY*T~ZgesW2!N8f!?KNG7=E=tcUG)@j#B8n0Qu_kPd+W8d?fV3IcX95)k@XkX2&^L#dh< vU-_~K%>e=Fn#)lM07i=dY*#+U44{bsGk`1tg$Ym)r~urI0s#O32)r@Ts*p)) literal 0 HcmV?d00001 From f725960c51a5f0faf99e7747d766c6213f6f3186 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 25 Sep 2024 14:18:55 +0000 Subject: [PATCH 54/71] Update fixture replacement test --- tempodb/backend/test/backend_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tempodb/backend/test/backend_test.go b/tempodb/backend/test/backend_test.go index 91df61ef29b..f3f7143d549 100644 --- a/tempodb/backend/test/backend_test.go +++ b/tempodb/backend/test/backend_test.go @@ -31,10 +31,10 @@ func TestFixtures(t *testing.T) { // To regenerate the fixtures, uncomment the write path. // metas := []*backend.BlockMeta{ - // backend.NewBlockMeta(tenant, uuid.New().UUID, "v1", backend.EncGZIP, "adsf"), - // backend.NewBlockMeta(tenant, uuid.New().UUID, "v2", backend.EncNone, "adsf"), - // backend.NewBlockMeta(tenant, uuid.New().UUID, "v3", backend.EncLZ4_4M, "adsf"), - // backend.NewBlockMeta(tenant, uuid.New().UUID, "v4", backend.EncLZ4_1M, "adsf"), + // backend.NewBlockMeta(tenant, uuid.New(), "v1", backend.EncGZIP, "adsf"), + // backend.NewBlockMeta(tenant, uuid.New(), "v2", backend.EncNone, "adsf"), + // backend.NewBlockMeta(tenant, uuid.New(), "v3", backend.EncLZ4_4M, "adsf"), + // backend.NewBlockMeta(tenant, uuid.New(), "v4", backend.EncLZ4_1M, "adsf"), // } // // for _, meta := range metas { @@ -42,7 +42,7 @@ func TestFixtures(t *testing.T) { // require.NoError(t, err) // } // - // err = rc.MarkBlockCompacted(metas[0].BlockID.UUID, tenant) + // err = rc.MarkBlockCompacted((uuid.UUID)(metas[0].BlockID), tenant) // assert.NoError(t, err) listMetas, listCompactedMetas, err := rr.ListBlocks(ctx, tenant) From 6238b0cf74a542437b5ba291acd35afe835af5f4 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 25 Sep 2024 15:05:25 +0000 Subject: [PATCH 55/71] Improve error handling and fix test --- tempodb/backend/raw.go | 7 ++++--- tempodb/backend/raw_test.go | 2 +- tempodb/backend/tenantindex.go | 5 +++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tempodb/backend/raw.go b/tempodb/backend/raw.go index 85e96ca0c33..dcb824f81eb 100644 --- a/tempodb/backend/raw.go +++ b/tempodb/backend/raw.go @@ -5,6 +5,7 @@ import ( "context" "encoding/json" "errors" + "fmt" "io" "path" "time" @@ -236,19 +237,19 @@ func (r *reader) TenantIndex(ctx context.Context, tenantID string) (*TenantIndex func (r *reader) tenantIndexProto(ctx context.Context, tenantID string) (*TenantIndex, error) { readerPb, size, err := r.r.Read(ctx, TenantIndexNamePb, KeyPath([]string{tenantID}), nil) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to read tenant index proto: %w", err) } defer readerPb.Close() bytesPb, err := tempo_io.ReadAllWithEstimate(readerPb, size) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to read all with estimate: %w", err) } out := &TenantIndex{} err = out.unmarshalPb(bytesPb) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to unmarshal tenant index proto: %w", err) } return out, nil diff --git a/tempodb/backend/raw_test.go b/tempodb/backend/raw_test.go index d843d12a30e..f7e4cd055ce 100644 --- a/tempodb/backend/raw_test.go +++ b/tempodb/backend/raw_test.go @@ -124,7 +124,7 @@ func TestReader(t *testing.T) { assert.Nil(t, idx) expectedIdx := newTenantIndex([]*BlockMeta{expectedMeta}, nil) - m.R, _ = expectedIdx.marshal() + m.R, _ = expectedIdx.marshalPb() idx, err = r.TenantIndex(ctx, "test") assert.NoError(t, err) assert.True(t, cmp.Equal(expectedIdx, idx)) diff --git a/tempodb/backend/tenantindex.go b/tempodb/backend/tenantindex.go index 1ea5f35bc97..7604c5b7cdb 100644 --- a/tempodb/backend/tenantindex.go +++ b/tempodb/backend/tenantindex.go @@ -3,6 +3,7 @@ package backend import ( "bytes" "encoding/json" + "fmt" "time" proto "github.com/gogo/protobuf/proto" @@ -90,12 +91,12 @@ func (b *TenantIndex) marshalPb() ([]byte, error) { func (b *TenantIndex) unmarshalPb(buffer []byte) error { decoder, err := zstd.NewReader(nil, zstd.WithDecoderConcurrency(0)) if err != nil { - return err + return fmt.Errorf("error creating zstd decoder: %w", err) } bb, err := decoder.DecodeAll(buffer, nil) if err != nil { - return err + return fmt.Errorf("error decoding zstd: %w", err) } return b.Unmarshal(bb) From 8d6f76f6fee6b10250b38662a0dcfbff7c0dc5ed Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 25 Sep 2024 15:13:34 +0000 Subject: [PATCH 56/71] Extend test for tenantindex round-trip --- tempodb/backend/tenantindex_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tempodb/backend/tenantindex_test.go b/tempodb/backend/tenantindex_test.go index cf26e102b1d..654c6ab5cbe 100644 --- a/tempodb/backend/tenantindex_test.go +++ b/tempodb/backend/tenantindex_test.go @@ -84,6 +84,20 @@ func TestIndexMarshalUnmarshal(t *testing.T) { // assert.Equal(t, tc.idx, actual) assert.True(t, cmp.Equal(tc.idx, actual)) } + + for _, tc := range tests { + // proto + buff, err := tc.idx.marshalPb() + require.NoError(t, err) + + actual := &TenantIndex{} + err = actual.unmarshalPb(buff) + require.NoError(t, err) + + // cmp.Equal used due to time marshalling: https://github.com/stretchr/testify/issues/502 + // assert.Equal(t, tc.idx, actual) + assert.True(t, cmp.Equal(tc.idx, actual)) + } } func TestIndexUnmarshalErrors(t *testing.T) { From edd192339a54005100b0832c2b6a948f9ddfd915 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 25 Sep 2024 18:52:22 +0000 Subject: [PATCH 57/71] Small fixes --- tempodb/backend/raw_test.go | 3 --- tempodb/blocklist/poller.go | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/tempodb/backend/raw_test.go b/tempodb/backend/raw_test.go index f7e4cd055ce..6a74aa612bd 100644 --- a/tempodb/backend/raw_test.go +++ b/tempodb/backend/raw_test.go @@ -218,7 +218,4 @@ func TestRoundTripMeta(t *testing.T) { err = json.Unmarshal(jsonBytes, expected2) assert.NoError(t, err) assert.Equal(t, meta, expected2) - - // Does json have the same object as proto? - assert.Equal(t, meta, expected2, expectedPb2, expectedPb3) } diff --git a/tempodb/blocklist/poller.go b/tempodb/blocklist/poller.go index 4f0e5207b36..e2fc1ed2751 100644 --- a/tempodb/blocklist/poller.go +++ b/tempodb/blocklist/poller.go @@ -42,7 +42,7 @@ var ( metricBackendBytes = promauto.NewGaugeVec(prometheus.GaugeOpts{ Namespace: "tempodb", Name: "backend_bytes_total", - Help: "Total number of bytes in the ", + Help: "Total number of bytes in the backend", }, []string{"tenant", "status"}) metricBlocklistErrors = promauto.NewCounterVec(prometheus.CounterOpts{ Namespace: "tempodb", From 9a77da07a1b180ec16a06a551107a7a2700fdb18 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 25 Sep 2024 18:54:35 +0000 Subject: [PATCH 58/71] Revert "Drop json fallback from tenantindex read" This reverts commit 834ff5b85d8a8a4d7eb560fbb67ba8f3a5a3959a. --- tempodb/backend/backend.go | 4 ++++ tempodb/backend/raw.go | 29 ++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/tempodb/backend/backend.go b/tempodb/backend/backend.go index c3a49444b6f..93a1f006d47 100644 --- a/tempodb/backend/backend.go +++ b/tempodb/backend/backend.go @@ -6,6 +6,7 @@ import ( "io" "github.com/google/uuid" + "go.opentelemetry.io/otel" "github.com/grafana/tempo/pkg/cache" ) @@ -24,6 +25,9 @@ var ( ErrBadSeedFile = fmt.Errorf("bad seed file") GlobalMaxBlockID = uuid.MustParse("ffffffff-ffff-ffff-ffff-ffffffffffff") + + tracer = otel.Tracer("backend") + EventJSONFallback = "falling back to json" ) type CacheInfo struct { diff --git a/tempodb/backend/raw.go b/tempodb/backend/raw.go index dcb824f81eb..d1fa8b69980 100644 --- a/tempodb/backend/raw.go +++ b/tempodb/backend/raw.go @@ -231,7 +231,34 @@ func (r *reader) BlockMeta(ctx context.Context, blockID uuid.UUID, tenantID stri // TenantIndex implements backend.Reader func (r *reader) TenantIndex(ctx context.Context, tenantID string) (*TenantIndex, error) { - return r.tenantIndexProto(ctx, tenantID) + ctx, span := tracer.Start(ctx, "reader.TenantIndex") + defer span.End() + + outPb, err := r.tenantIndexProto(ctx, tenantID) + if err == nil { + return outPb, nil + } + + span.AddEvent(EventJSONFallback) + + readerJ, size, err := r.r.Read(ctx, TenantIndexName, KeyPath([]string{tenantID}), nil) + if err != nil { + return nil, err + } + defer readerJ.Close() + + bytesJ, err := tempo_io.ReadAllWithEstimate(readerJ, size) + if err != nil { + return nil, err + } + + i := &TenantIndex{} + err = i.unmarshal(bytesJ) + if err != nil { + return nil, err + } + + return i, nil } func (r *reader) tenantIndexProto(ctx context.Context, tenantID string) (*TenantIndex, error) { From 56701219a7a8a160462d982964d7af32a18cf31d Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 25 Sep 2024 19:37:21 +0000 Subject: [PATCH 59/71] Add back mocks to capture multiple backend writes --- tempodb/backend/mocks.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tempodb/backend/mocks.go b/tempodb/backend/mocks.go index 15f5dcbc836..5b747fe6412 100644 --- a/tempodb/backend/mocks.go +++ b/tempodb/backend/mocks.go @@ -72,7 +72,7 @@ func (m *MockRawReader) Shutdown() {} // MockRawWriter type MockRawWriter struct { - writeBuffer []byte + writeBuffer [][]byte appendBuffer []byte closeAppendCalled bool deleteCalls map[string]map[string]int @@ -80,8 +80,13 @@ type MockRawWriter struct { } func (m *MockRawWriter) Write(_ context.Context, _ string, _ KeyPath, data io.Reader, size int64, _ *CacheInfo) error { - var err error - m.writeBuffer, err = tempo_io.ReadAllWithEstimate(data, size) + if m.writeBuffer == nil { + m.writeBuffer = make([][]byte, 0) + } + + writeBuffer, err := tempo_io.ReadAllWithEstimate(data, size) + m.writeBuffer = append(m.writeBuffer, writeBuffer) + return err } From de521542b2631c74d9801eb96cff8ec34fcd65df Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 25 Sep 2024 19:42:17 +0000 Subject: [PATCH 60/71] Add back proto & json writitng/reading for tenantindex --- tempodb/backend/raw.go | 14 +++++++++++++- tempodb/backend/raw_test.go | 25 ++++++++++++++++++------- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/tempodb/backend/raw.go b/tempodb/backend/raw.go index d1fa8b69980..a3c68ef034b 100644 --- a/tempodb/backend/raw.go +++ b/tempodb/backend/raw.go @@ -143,12 +143,24 @@ func (w *writer) WriteTenantIndex(ctx context.Context, tenantID string, meta []* b := newTenantIndex(meta, compactedMeta) + // Marshal and write the proto object. indexBytesPb, err := b.marshalPb() if err != nil { return err } - return w.w.Write(ctx, TenantIndexNamePb, KeyPath([]string{tenantID}), bytes.NewReader(indexBytesPb), int64(len(indexBytesPb)), nil) + err = w.w.Write(ctx, TenantIndexNamePb, KeyPath([]string{tenantID}), bytes.NewReader(indexBytesPb), int64(len(indexBytesPb)), nil) + if err != nil { + return err + } + + // Marshal and write the JSON object. + indexBytesJSON, err := b.marshal() + if err != nil { + return err + } + + return w.w.Write(ctx, TenantIndexName, KeyPath([]string{tenantID}), bytes.NewReader(indexBytesJSON), int64(len(indexBytesJSON)), nil) } // Delete implements backend.Writer diff --git a/tempodb/backend/raw_test.go b/tempodb/backend/raw_test.go index 6a74aa612bd..04f9500b53c 100644 --- a/tempodb/backend/raw_test.go +++ b/tempodb/backend/raw_test.go @@ -25,7 +25,7 @@ func TestWriter(t *testing.T) { err := w.Write(ctx, "test", uuid.New(), "test", expected, nil) assert.NoError(t, err) - assert.Equal(t, expected, m.writeBuffer) + assert.Equal(t, expected, m.writeBuffer[len(m.writeBuffer)-1]) _, err = w.Append(ctx, "test", uuid.New(), "test", nil, expected) assert.NoError(t, err) @@ -38,23 +38,34 @@ func TestWriter(t *testing.T) { meta := NewBlockMeta("test", uuid.New(), "blerg", EncGZIP, "glarg") jsonBytes, err := json.Marshal(meta) assert.NoError(t, err) + assert.NoError(t, err) // Write the block meta to the backend and validate the payloads. err = w.WriteBlockMeta(ctx, meta) assert.NoError(t, err) - assert.Equal(t, jsonBytes, m.writeBuffer) + assert.Equal(t, jsonBytes, m.writeBuffer[len(m.writeBuffer)-1]) // Write the tenant index to the backend and validate the payloads. err = w.WriteTenantIndex(ctx, "test", []*BlockMeta{meta}, nil) assert.NoError(t, err) - idx := &TenantIndex{} - err = idx.unmarshalPb(m.writeBuffer) + // proto + idxP := &TenantIndex{} + err = idxP.unmarshalPb(m.writeBuffer[len(m.writeBuffer)-2]) + assert.NoError(t, err) + + assert.Equal(t, []*BlockMeta{meta}, idxP.Meta) + assert.True(t, cmp.Equal([]*BlockMeta{meta}, idxP.Meta)) // using cmp.Equal to compare json datetimes + assert.True(t, cmp.Equal([]*CompactedBlockMeta(nil), idxP.CompactedMeta)) // using cmp.Equal to compare json datetimes + + // json + idxJ := &TenantIndex{} + err = idxJ.unmarshal(m.writeBuffer[len(m.writeBuffer)-1]) assert.NoError(t, err) - assert.Equal(t, []*BlockMeta{meta}, idx.Meta) - assert.True(t, cmp.Equal([]*BlockMeta{meta}, idx.Meta)) // using cmp.Equal to compare json datetimes - assert.True(t, cmp.Equal([]*CompactedBlockMeta(nil), idx.CompactedMeta)) // using cmp.Equal to compare json datetimes + assert.Equal(t, []*BlockMeta{meta}, idxJ.Meta) + assert.True(t, cmp.Equal([]*BlockMeta{meta}, idxJ.Meta)) // using cmp.Equal to compare json datetimes + assert.True(t, cmp.Equal([]*CompactedBlockMeta(nil), idxJ.CompactedMeta)) // using cmp.Equal to compare json datetimes // When there are no blocks, the tenant index should be deleted assert.Equal(t, map[string]map[string]int(nil), w.(*writer).w.(*MockRawWriter).deleteCalls) From b6548ac81b8aa5777c13b78004cbc1097a6aa3d7 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 25 Sep 2024 19:59:59 +0000 Subject: [PATCH 61/71] 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. --- cmd/tempo-cli/cmd-list-compactionsummary.go | 6 +- tempodb/backend/block_meta_test.go | 2 +- tempodb/backend/v1.pb.go | 102 +++++++++--------- tempodb/backend/v1/v1.proto | 2 +- tempodb/compactor_test.go | 2 +- tempodb/encoding/v2/compactor.go | 4 +- tempodb/encoding/v2/streaming_block_test.go | 4 +- tempodb/encoding/v2/wal_block.go | 2 +- .../vparquet2/block_findtracebyid_test.go | 2 +- .../encoding/vparquet2/block_iterator_test.go | 2 +- tempodb/encoding/vparquet2/compactor.go | 4 +- tempodb/encoding/vparquet2/compactor_test.go | 2 +- .../vparquet3/block_findtracebyid_test.go | 2 +- .../encoding/vparquet3/block_iterator_test.go | 2 +- tempodb/encoding/vparquet3/compactor.go | 4 +- tempodb/encoding/vparquet3/compactor_test.go | 4 +- .../vparquet4/block_findtracebyid_test.go | 2 +- .../encoding/vparquet4/block_iterator_test.go | 2 +- tempodb/encoding/vparquet4/compactor.go | 4 +- tempodb/encoding/vparquet4/compactor_test.go | 4 +- 20 files changed, 79 insertions(+), 79 deletions(-) diff --git a/cmd/tempo-cli/cmd-list-compactionsummary.go b/cmd/tempo-cli/cmd-list-compactionsummary.go index 9ebdffd7887..ada11e4ec31 100644 --- a/cmd/tempo-cli/cmd-list-compactionsummary.go +++ b/cmd/tempo-cli/cmd-list-compactionsummary.go @@ -61,9 +61,9 @@ func displayCompactionSummary(results []blockStats) { sizeSum := uint64(0) sizeMin := uint64(0) sizeMax := uint64(0) - countSum := int32(0) - countMin := int32(0) - countMax := int32(0) + countSum := int64(0) + countMin := int64(0) + countMax := int64(0) countBloomShards := 0 var newest time.Time diff --git a/tempodb/backend/block_meta_test.go b/tempodb/backend/block_meta_test.go index 11a9b9aaff1..62ef8d3d611 100644 --- a/tempodb/backend/block_meta_test.go +++ b/tempodb/backend/block_meta_test.go @@ -41,7 +41,7 @@ func TestBlockMetaObjectAdded(t *testing.T) { ends []uint32 expectedStart time.Time expectedEnd time.Time - expectedObjects int32 + expectedObjects int64 }{ {}, { diff --git a/tempodb/backend/v1.pb.go b/tempodb/backend/v1.pb.go index 828bb90307b..9646402569b 100644 --- a/tempodb/backend/v1.pb.go +++ b/tempodb/backend/v1.pb.go @@ -33,7 +33,7 @@ type BlockMeta struct { TenantID string `protobuf:"bytes,5,opt,name=tenant_id,json=tenantId,proto3" json:"tenantID"` StartTime time.Time `protobuf:"bytes,6,opt,name=start_time,json=startTime,proto3,stdtime" json:"startTime"` EndTime time.Time `protobuf:"bytes,7,opt,name=end_time,json=endTime,proto3,stdtime" json:"endTime"` - TotalObjects int32 `protobuf:"varint,8,opt,name=total_objects,json=totalObjects,proto3" json:"totalObjects"` + TotalObjects int64 `protobuf:"varint,8,opt,name=total_objects,json=totalObjects,proto3" json:"totalObjects"` Size_ uint64 `protobuf:"varint,9,opt,name=size,proto3" json:"size,omitempty"` CompactionLevel uint32 `protobuf:"varint,10,opt,name=compaction_level,json=compactionLevel,proto3" json:"compactionLevel"` Encoding Encoding `protobuf:"bytes,11,opt,name=encoding,proto3,customtype=Encoding" json:"encoding"` @@ -108,7 +108,7 @@ func (m *BlockMeta) GetEndTime() time.Time { return time.Time{} } -func (m *BlockMeta) GetTotalObjects() int32 { +func (m *BlockMeta) GetTotalObjects() int64 { if m != nil { return m.TotalObjects } @@ -287,54 +287,54 @@ func init() { proto.RegisterFile("tempodb/backend/v1/v1.proto", fileDescriptor_6 var fileDescriptor_6bc10ae735c1a340 = []byte{ // 778 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0xdd, 0x8a, 0xdb, 0x46, - 0x14, 0xb6, 0x36, 0xce, 0xda, 0x1e, 0xdb, 0x6b, 0x7b, 0x42, 0x40, 0x75, 0xc0, 0x63, 0x4c, 0x2f, - 0x1c, 0x48, 0x65, 0x36, 0x25, 0x85, 0x52, 0x5a, 0xa8, 0x76, 0x53, 0x48, 0xe9, 0x4f, 0x50, 0x92, - 0x9b, 0x52, 0x10, 0x23, 0xcd, 0x58, 0x51, 0x23, 0x69, 0x8c, 0x34, 0x36, 0x6d, 0x9e, 0x22, 0x4f, - 0xd3, 0x67, 0x08, 0xbd, 0xda, 0xde, 0x95, 0x5e, 0x4c, 0x8b, 0xf7, 0x4e, 0x4f, 0x51, 0xe6, 0x48, - 0x96, 0x6c, 0x2f, 0x65, 0x73, 0x77, 0xce, 0xf9, 0xce, 0x77, 0x66, 0xbe, 0xa3, 0xf9, 0x84, 0x1e, - 0x48, 0x1e, 0xaf, 0x04, 0xf3, 0x16, 0x1e, 0xf5, 0xdf, 0xf0, 0x84, 0x2d, 0x36, 0xe7, 0x8b, 0xcd, - 0xb9, 0xb5, 0x4a, 0x85, 0x14, 0x18, 0x95, 0x45, 0x6b, 0x73, 0x3e, 0x26, 0x81, 0x10, 0x41, 0xc4, - 0x17, 0x80, 0x78, 0xeb, 0xe5, 0x42, 0x86, 0x31, 0xcf, 0x24, 0x8d, 0x57, 0x45, 0xf3, 0xf8, 0x93, - 0x20, 0x94, 0xaf, 0xd7, 0x9e, 0xe5, 0x8b, 0x78, 0x11, 0x88, 0x40, 0xd4, 0x9d, 0x3a, 0x83, 0x04, - 0xa2, 0xa2, 0x7d, 0xf6, 0x47, 0x0b, 0x75, 0xec, 0x48, 0xf8, 0x6f, 0xbe, 0xe7, 0x92, 0xe2, 0x8f, - 0x51, 0x6b, 0xc3, 0xd3, 0x2c, 0x14, 0x89, 0x69, 0x4c, 0x8d, 0x79, 0xc7, 0x46, 0xb9, 0x22, 0xa7, - 0x4b, 0x91, 0xc6, 0x54, 0x3a, 0x3b, 0x08, 0x7f, 0x89, 0xda, 0x9e, 0xa6, 0xb8, 0x21, 0x33, 0x4f, - 0xa6, 0xc6, 0xbc, 0x67, 0xcf, 0xde, 0x2b, 0xd2, 0xf8, 0x5b, 0x91, 0xe6, 0xab, 0x57, 0xcf, 0x2e, - 0xb7, 0x8a, 0xb4, 0x60, 0xe4, 0xb3, 0xcb, 0x5c, 0x91, 0x96, 0x57, 0x84, 0x4e, 0x19, 0x30, 0xfc, - 0x04, 0x75, 0x24, 0x4f, 0x68, 0x22, 0x35, 0xff, 0x2e, 0x1c, 0x63, 0x6e, 0x15, 0x69, 0xbf, 0x84, - 0x22, 0x90, 0xda, 0xb2, 0x8c, 0x9d, 0x5d, 0xc4, 0xf0, 0x73, 0x84, 0x32, 0x49, 0x53, 0xe9, 0x6a, - 0xc5, 0xe6, 0xe9, 0xd4, 0x98, 0x77, 0x1f, 0x8f, 0xad, 0x62, 0x1d, 0xd6, 0x4e, 0xa4, 0xf5, 0x72, - 0xb7, 0x0e, 0xfb, 0xbe, 0xbe, 0x53, 0xae, 0x48, 0x07, 0x58, 0xba, 0xfe, 0xee, 0x1f, 0x62, 0x38, - 0x75, 0x8a, 0xbf, 0x45, 0x6d, 0x9e, 0xb0, 0x62, 0x5e, 0xeb, 0xd6, 0x79, 0xf7, 0xca, 0x79, 0x2d, - 0x9e, 0xb0, 0x6a, 0xda, 0x2e, 0xc1, 0x4f, 0x50, 0x5f, 0x0a, 0x49, 0x23, 0x57, 0x78, 0xbf, 0x70, - 0x5f, 0x66, 0x66, 0x7b, 0x6a, 0xcc, 0xef, 0xda, 0xc3, 0x5c, 0x91, 0x1e, 0x00, 0x3f, 0x16, 0x75, - 0xe7, 0x20, 0xc3, 0x18, 0x35, 0xb3, 0xf0, 0x2d, 0x37, 0x3b, 0x53, 0x63, 0xde, 0x74, 0x20, 0xc6, - 0x5f, 0xa1, 0xa1, 0x2f, 0xe2, 0x15, 0xf5, 0x65, 0x28, 0x12, 0x37, 0xe2, 0x1b, 0x1e, 0x99, 0x68, - 0x6a, 0xcc, 0xfb, 0xf6, 0xbd, 0x5c, 0x91, 0x41, 0x8d, 0x7d, 0xa7, 0x21, 0xe7, 0xb8, 0x80, 0x1f, - 0x69, 0x59, 0xbe, 0x60, 0x61, 0x12, 0x98, 0x5d, 0xf8, 0x3c, 0xc3, 0xf2, 0xf3, 0xb4, 0x9f, 0x96, - 0x75, 0xa7, 0xea, 0xc0, 0x9f, 0xa3, 0x41, 0x98, 0x30, 0xfe, 0xab, 0xbb, 0xa2, 0x01, 0x77, 0xe1, - 0x32, 0x3d, 0x38, 0x6c, 0x94, 0x2b, 0xd2, 0x07, 0xe8, 0x39, 0x0d, 0xf8, 0x8b, 0xf0, 0x2d, 0x77, - 0x0e, 0xd3, 0x5a, 0x73, 0xca, 0x7d, 0x91, 0xb2, 0xcc, 0xec, 0x03, 0xb1, 0xd6, 0xec, 0x14, 0x75, - 0xe7, 0x20, 0xd3, 0x34, 0x46, 0x25, 0x75, 0xab, 0x4b, 0x9e, 0xc1, 0x1b, 0x00, 0x9a, 0x06, 0xaa, - 0x4b, 0x1e, 0x64, 0xf8, 0x0b, 0x34, 0xf2, 0x22, 0x21, 0x62, 0x37, 0x7b, 0x4d, 0x53, 0xe6, 0xfa, - 0x62, 0x9d, 0x48, 0x73, 0x00, 0x27, 0x0e, 0x72, 0x45, 0xba, 0x00, 0xbe, 0xd0, 0x58, 0xe6, 0x0c, - 0xea, 0xe4, 0x42, 0xf7, 0xe1, 0x05, 0xea, 0x2e, 0x85, 0x90, 0x3c, 0x2d, 0x14, 0x0e, 0x81, 0x76, - 0x96, 0x2b, 0x82, 0x8a, 0x32, 0xc8, 0xdb, 0x8b, 0xb1, 0x8f, 0x46, 0x8c, 0xb3, 0xd0, 0xa7, 0x92, - 0xeb, 0xb3, 0xa2, 0x75, 0x9c, 0x64, 0xe6, 0x08, 0xb6, 0xf9, 0x59, 0xb9, 0xcd, 0xe1, 0xe5, 0xae, - 0xe1, 0xa2, 0xc0, 0x73, 0x45, 0xc6, 0xec, 0xa8, 0xf6, 0x48, 0xc4, 0xa1, 0xf6, 0xb6, 0xfc, 0xcd, - 0x19, 0x1e, 0x63, 0xf8, 0x07, 0x84, 0x53, 0xbe, 0x8a, 0x74, 0x51, 0x7f, 0xea, 0x25, 0xf5, 0xa5, - 0x48, 0x4d, 0x0c, 0x97, 0x23, 0xb9, 0x22, 0x0f, 0xf6, 0xd0, 0x6f, 0x00, 0xdc, 0x1b, 0x37, 0xba, - 0x01, 0xce, 0x7e, 0x37, 0x10, 0xbe, 0x28, 0x5e, 0x03, 0x67, 0xb5, 0xab, 0x6d, 0x84, 0x0a, 0xbf, - 0xc6, 0x5c, 0x52, 0x30, 0x76, 0xf7, 0xf1, 0x7d, 0xab, 0xfe, 0xa9, 0x58, 0x55, 0xab, 0xdd, 0xd3, - 0xda, 0xae, 0x14, 0x31, 0x72, 0x45, 0x1a, 0x4e, 0xc7, 0xab, 0x66, 0xfc, 0x8c, 0xce, 0xfc, 0xdd, - 0xe4, 0xc2, 0x31, 0x27, 0xb7, 0x3a, 0xe6, 0xa3, 0xd2, 0x31, 0xfd, 0x8a, 0x59, 0xf9, 0xe6, 0xb0, - 0x34, 0xfb, 0xd3, 0x40, 0xdd, 0xd2, 0xfe, 0xfa, 0x85, 0x69, 0xaf, 0xfb, 0x29, 0x87, 0xdd, 0x53, - 0x59, 0xde, 0xf8, 0x83, 0xbc, 0x5e, 0xb2, 0xbe, 0x96, 0x85, 0xd7, 0xab, 0x14, 0x3f, 0x44, 0x4d, - 0x50, 0x7f, 0x32, 0xbd, 0xf3, 0xbf, 0xea, 0x1d, 0x68, 0xc1, 0x4f, 0xf7, 0xa5, 0x02, 0xe9, 0x0e, - 0x90, 0x26, 0xfb, 0xa4, 0x9b, 0x6b, 0xde, 0xd3, 0x04, 0xab, 0x7c, 0xf8, 0x7e, 0x3b, 0x31, 0xae, - 0xb6, 0x13, 0xe3, 0xdf, 0xed, 0xc4, 0x78, 0x77, 0x3d, 0x69, 0x5c, 0x5d, 0x4f, 0x1a, 0x7f, 0x5d, - 0x4f, 0x1a, 0x3f, 0x0d, 0x8e, 0x7e, 0xf6, 0xde, 0x29, 0x48, 0xfa, 0xf4, 0xbf, 0x00, 0x00, 0x00, - 0xff, 0xff, 0x3f, 0xb9, 0xc7, 0xff, 0x06, 0x06, 0x00, 0x00, + 0x14, 0xb6, 0x76, 0xdd, 0xb5, 0x3d, 0xb6, 0xd7, 0xf6, 0x84, 0x80, 0xea, 0x80, 0xc7, 0x98, 0x5e, + 0x38, 0x90, 0xca, 0x6c, 0x4a, 0x0a, 0xa5, 0xb4, 0x50, 0xed, 0xa6, 0x90, 0xd2, 0x9f, 0xa0, 0x24, + 0x37, 0xa5, 0x20, 0x46, 0x9a, 0xb1, 0xa2, 0x46, 0xd2, 0x18, 0x69, 0x6c, 0xda, 0x3c, 0x45, 0x9e, + 0xa6, 0xcf, 0x10, 0x7a, 0xb5, 0xbd, 0x2b, 0xbd, 0x98, 0x16, 0xef, 0x9d, 0x9e, 0xa2, 0xcc, 0x91, + 0x2c, 0xd9, 0x5e, 0xca, 0xf6, 0xee, 0x9c, 0xf3, 0x9d, 0xef, 0xcc, 0x7c, 0x47, 0xf3, 0x09, 0x3d, + 0x90, 0x3c, 0x5e, 0x09, 0xe6, 0x2d, 0x3c, 0xea, 0xbf, 0xe1, 0x09, 0x5b, 0x6c, 0x2e, 0x16, 0x9b, + 0x0b, 0x6b, 0x95, 0x0a, 0x29, 0x30, 0x2a, 0x8b, 0xd6, 0xe6, 0x62, 0x4c, 0x02, 0x21, 0x82, 0x88, + 0x2f, 0x00, 0xf1, 0xd6, 0xcb, 0x85, 0x0c, 0x63, 0x9e, 0x49, 0x1a, 0xaf, 0x8a, 0xe6, 0xf1, 0xc7, + 0x41, 0x28, 0x5f, 0xaf, 0x3d, 0xcb, 0x17, 0xf1, 0x22, 0x10, 0x81, 0xa8, 0x3b, 0x75, 0x06, 0x09, + 0x44, 0x45, 0xfb, 0xec, 0xf7, 0x16, 0xea, 0xd8, 0x91, 0xf0, 0xdf, 0x7c, 0xc7, 0x25, 0xc5, 0x1f, + 0xa1, 0xd6, 0x86, 0xa7, 0x59, 0x28, 0x12, 0xd3, 0x98, 0x1a, 0xf3, 0x8e, 0x8d, 0x72, 0x45, 0xce, + 0x96, 0x22, 0x8d, 0xa9, 0x74, 0x76, 0x10, 0xfe, 0x02, 0xb5, 0x3d, 0x4d, 0x71, 0x43, 0x66, 0x9e, + 0x4c, 0x8d, 0x79, 0xcf, 0x9e, 0xbd, 0x57, 0xa4, 0xf1, 0x97, 0x22, 0xcd, 0x57, 0xaf, 0x9e, 0x5d, + 0x6d, 0x15, 0x69, 0xc1, 0xc8, 0x67, 0x57, 0xb9, 0x22, 0x2d, 0xaf, 0x08, 0x9d, 0x32, 0x60, 0xf8, + 0x09, 0xea, 0x48, 0x9e, 0xd0, 0x44, 0x6a, 0xfe, 0x07, 0x70, 0x8c, 0xb9, 0x55, 0xa4, 0xfd, 0x12, + 0x8a, 0x40, 0x6a, 0xcb, 0x32, 0x76, 0x76, 0x11, 0xc3, 0xcf, 0x11, 0xca, 0x24, 0x4d, 0xa5, 0xab, + 0x15, 0x9b, 0x67, 0x53, 0x63, 0xde, 0x7d, 0x3c, 0xb6, 0x8a, 0x75, 0x58, 0x3b, 0x91, 0xd6, 0xcb, + 0xdd, 0x3a, 0xec, 0xfb, 0xfa, 0x4e, 0xb9, 0x22, 0x1d, 0x60, 0xe9, 0xfa, 0xbb, 0xbf, 0x89, 0xe1, + 0xd4, 0x29, 0xfe, 0x06, 0xb5, 0x79, 0xc2, 0x8a, 0x79, 0xad, 0x3b, 0xe7, 0xdd, 0x2b, 0xe7, 0xb5, + 0x78, 0xc2, 0xaa, 0x69, 0xbb, 0x04, 0x3f, 0x41, 0x7d, 0x29, 0x24, 0x8d, 0x5c, 0xe1, 0xfd, 0xcc, + 0x7d, 0x99, 0x99, 0xed, 0xa9, 0x31, 0x3f, 0xb5, 0x87, 0xb9, 0x22, 0x3d, 0x00, 0x7e, 0x28, 0xea, + 0xce, 0x41, 0x86, 0x31, 0x6a, 0x66, 0xe1, 0x5b, 0x6e, 0x76, 0xa6, 0xc6, 0xbc, 0xe9, 0x40, 0x8c, + 0xbf, 0x44, 0x43, 0x5f, 0xc4, 0x2b, 0xea, 0xcb, 0x50, 0x24, 0x6e, 0xc4, 0x37, 0x3c, 0x32, 0xd1, + 0xd4, 0x98, 0xf7, 0xed, 0x7b, 0xb9, 0x22, 0x83, 0x1a, 0xfb, 0x56, 0x43, 0xce, 0x71, 0x01, 0x3f, + 0xd2, 0xb2, 0x7c, 0xc1, 0xc2, 0x24, 0x30, 0xbb, 0xf0, 0x79, 0x86, 0xe5, 0xe7, 0x69, 0x3f, 0x2d, + 0xeb, 0x4e, 0xd5, 0x81, 0x3f, 0x43, 0x83, 0x30, 0x61, 0xfc, 0x17, 0x77, 0x45, 0x03, 0xee, 0xc2, + 0x65, 0x7a, 0x70, 0xd8, 0x28, 0x57, 0xa4, 0x0f, 0xd0, 0x73, 0x1a, 0xf0, 0x17, 0xe1, 0x5b, 0xee, + 0x1c, 0xa6, 0xb5, 0xe6, 0x94, 0xfb, 0x22, 0x65, 0x99, 0xd9, 0x07, 0x62, 0xad, 0xd9, 0x29, 0xea, + 0xce, 0x41, 0xa6, 0x69, 0x8c, 0x4a, 0xea, 0x56, 0x97, 0x3c, 0x87, 0x37, 0x00, 0x34, 0x0d, 0x54, + 0x97, 0x3c, 0xc8, 0xf0, 0xe7, 0x68, 0xe4, 0x45, 0x42, 0xc4, 0x6e, 0xf6, 0x9a, 0xa6, 0xcc, 0xf5, + 0xc5, 0x3a, 0x91, 0xe6, 0x00, 0x4e, 0x1c, 0xe4, 0x8a, 0x74, 0x01, 0x7c, 0xa1, 0xb1, 0xcc, 0x19, + 0xd4, 0xc9, 0xa5, 0xee, 0xc3, 0x0b, 0xd4, 0x5d, 0x0a, 0x21, 0x79, 0x5a, 0x28, 0x1c, 0x02, 0xed, + 0x3c, 0x57, 0x04, 0x15, 0x65, 0x90, 0xb7, 0x17, 0x63, 0x1f, 0x8d, 0x18, 0x67, 0xa1, 0x4f, 0x25, + 0xd7, 0x67, 0x45, 0xeb, 0x38, 0xc9, 0xcc, 0x11, 0x6c, 0xf3, 0xd3, 0x72, 0x9b, 0xc3, 0xab, 0x5d, + 0xc3, 0x65, 0x81, 0xe7, 0x8a, 0x8c, 0xd9, 0x51, 0xed, 0x91, 0x88, 0x43, 0xed, 0x6d, 0xf9, 0xab, + 0x33, 0x3c, 0xc6, 0xf0, 0xf7, 0x08, 0xa7, 0x7c, 0x15, 0xe9, 0xa2, 0xfe, 0xd4, 0x4b, 0xea, 0x4b, + 0x91, 0x9a, 0x18, 0x2e, 0x47, 0x72, 0x45, 0x1e, 0xec, 0xa1, 0x5f, 0x03, 0xb8, 0x37, 0x6e, 0x74, + 0x0b, 0x9c, 0xfd, 0x66, 0x20, 0x7c, 0x59, 0xbc, 0x06, 0xce, 0x6a, 0x57, 0xdb, 0x08, 0x15, 0x7e, + 0x8d, 0xb9, 0xa4, 0x60, 0xec, 0xee, 0xe3, 0xfb, 0x56, 0xfd, 0x53, 0xb1, 0xaa, 0x56, 0xbb, 0xa7, + 0xb5, 0x5d, 0x2b, 0x62, 0xe4, 0x8a, 0x34, 0x9c, 0x8e, 0x57, 0xcd, 0xf8, 0x09, 0x9d, 0xfb, 0xbb, + 0xc9, 0x85, 0x63, 0x4e, 0xee, 0x74, 0xcc, 0x87, 0xa5, 0x63, 0xfa, 0x15, 0xb3, 0xf2, 0xcd, 0x61, + 0x69, 0xf6, 0x87, 0x81, 0xba, 0xa5, 0xfd, 0xf5, 0x0b, 0xd3, 0x5e, 0xf7, 0x53, 0x0e, 0xbb, 0xa7, + 0xb2, 0xbc, 0xf1, 0xff, 0xf2, 0x7a, 0xc9, 0xfa, 0x4a, 0x16, 0x5e, 0xaf, 0x52, 0xfc, 0x10, 0x35, + 0x41, 0xfd, 0xc9, 0xf4, 0xf4, 0x3f, 0xd5, 0x3b, 0xd0, 0x82, 0x9f, 0xee, 0x4b, 0x05, 0xd2, 0x29, + 0x90, 0x26, 0xfb, 0xa4, 0xdb, 0x6b, 0xde, 0xd3, 0x04, 0xab, 0x7c, 0xf8, 0x7e, 0x3b, 0x31, 0xae, + 0xb7, 0x13, 0xe3, 0x9f, 0xed, 0xc4, 0x78, 0x77, 0x33, 0x69, 0x5c, 0xdf, 0x4c, 0x1a, 0x7f, 0xde, + 0x4c, 0x1a, 0x3f, 0x0e, 0x8e, 0x7e, 0xf6, 0xde, 0x19, 0x48, 0xfa, 0xe4, 0xdf, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xfe, 0x92, 0x00, 0xfe, 0x06, 0x06, 0x00, 0x00, } func (m *BlockMeta) Marshal() (dAtA []byte, err error) { @@ -887,7 +887,7 @@ func (m *BlockMeta) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.TotalObjects |= int32(b&0x7F) << shift + m.TotalObjects |= int64(b&0x7F) << shift if b < 0x80 { break } diff --git a/tempodb/backend/v1/v1.proto b/tempodb/backend/v1/v1.proto index 3f5b42824b3..b6617f1c8f6 100644 --- a/tempodb/backend/v1/v1.proto +++ b/tempodb/backend/v1/v1.proto @@ -13,7 +13,7 @@ message BlockMeta { string tenant_id = 5[(gogoproto.jsontag) = "tenantID", (gogoproto.customname) = "TenantID"]; google.protobuf.Timestamp start_time = 6[(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = "startTime"]; google.protobuf.Timestamp end_time = 7[(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = "endTime"]; - int32 total_objects = 8[(gogoproto.jsontag) = "totalObjects"]; + int64 total_objects = 8[(gogoproto.jsontag) = "totalObjects"]; uint64 size = 9; uint32 compaction_level = 10[(gogoproto.jsontag) = "compactionLevel"]; bytes encoding = 11[(gogoproto.customtype) = "Encoding", (gogoproto.nullable) = false]; diff --git a/tempodb/compactor_test.go b/tempodb/compactor_test.go index 9c57c00c62e..3ef1f679eb1 100644 --- a/tempodb/compactor_test.go +++ b/tempodb/compactor_test.go @@ -427,7 +427,7 @@ func TestCompactionUpdatesBlocklist(t *testing.T) { blocks := rw.blocklist.Metas(testTenantID) require.Equal(t, 1, len(blocks)) require.Equal(t, uint32(1), blocks[0].CompactionLevel) - require.Equal(t, int32(blockCount*recordCount), blocks[0].TotalObjects) + require.Equal(t, int64(blockCount*recordCount), blocks[0].TotalObjects) // Compacted list contains all old blocks require.Equal(t, blockCount, len(rw.blocklist.CompactedMetas(testTenantID))) diff --git a/tempodb/encoding/v2/compactor.go b/tempodb/encoding/v2/compactor.go index 1f8f9f055a3..f9731dd4db2 100644 --- a/tempodb/encoding/v2/compactor.go +++ b/tempodb/encoding/v2/compactor.go @@ -39,7 +39,7 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, }() var compactionLevel uint32 - var totalRecords int32 + var totalRecords int64 for _, blockMeta := range inputs { totalRecords += blockMeta.TotalObjects @@ -63,7 +63,7 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, nextCompactionLevel := compactionLevel + 1 - recordsPerBlock := (totalRecords / int32(c.opts.OutputBlocks)) + recordsPerBlock := (totalRecords / int64(c.opts.OutputBlocks)) combiner := c.opts.Combiner if combiner == nil { diff --git a/tempodb/encoding/v2/streaming_block_test.go b/tempodb/encoding/v2/streaming_block_test.go index 59db0b7cb8a..6db12dde07c 100644 --- a/tempodb/encoding/v2/streaming_block_test.go +++ b/tempodb/encoding/v2/streaming_block_test.go @@ -115,7 +115,7 @@ func TestStreamingBlockAddObject(t *testing.T) { assert.Equal(t, time.Unix(10000, 0), meta.StartTime) assert.Equal(t, time.Unix(25000, 0), meta.EndTime) assert.Equal(t, testTenantID, meta.TenantID) - assert.Equal(t, int32(numObjects), meta.TotalObjects) + assert.Equal(t, int64(numObjects), meta.TotalObjects) assert.Greater(t, meta.Size_, uint64(0)) assert.Greater(t, cb.bloom.GetShardCount(), 0) @@ -244,7 +244,7 @@ func streamingBlock(t *testing.T, cfg *common.BlockConfig, w backend.Writer) (*S originatingMeta.StartTime = time.Now().Add(-5 * time.Minute) originatingMeta.EndTime = time.Now().Add(5 * time.Minute) originatingMeta.DataEncoding = "foo" - originatingMeta.TotalObjects = int32(numMsgs) + originatingMeta.TotalObjects = int64(numMsgs) // calc expected records dataReader, err := NewDataReader(backend.NewContextReaderWithAllReader(bytes.NewReader(buffer.Bytes())), backend.EncNone) diff --git a/tempodb/encoding/v2/wal_block.go b/tempodb/encoding/v2/wal_block.go index f28818546de..df583670871 100644 --- a/tempodb/encoding/v2/wal_block.go +++ b/tempodb/encoding/v2/wal_block.go @@ -132,7 +132,7 @@ func openWALBlock(filename, path string, ingestionSlack, additionalStartSlack ti } b.appender = NewRecordAppender(records) - b.meta.TotalObjects = int32(b.appender.Length()) + b.meta.TotalObjects = int64(b.appender.Length()) b.meta.StartTime = time.Unix(int64(blockStart), 0) b.meta.EndTime = time.Unix(int64(blockEnd), 0) diff --git a/tempodb/encoding/vparquet2/block_findtracebyid_test.go b/tempodb/encoding/vparquet2/block_findtracebyid_test.go index d3c09b7e447..f471b9f5833 100644 --- a/tempodb/encoding/vparquet2/block_findtracebyid_test.go +++ b/tempodb/encoding/vparquet2/block_findtracebyid_test.go @@ -75,7 +75,7 @@ func TestBackendBlockFindTraceByID(t *testing.T) { }) meta := backend.NewBlockMeta("fake", uuid.New(), VersionString, backend.EncNone, "") - meta.TotalObjects = int32(len(traces)) + meta.TotalObjects = int64(len(traces)) s := newStreamingBlock(ctx, cfg, meta, r, w, tempo_io.NewBufferedWriter) // Write test data, occasionally flushing (cutting new row group) diff --git a/tempodb/encoding/vparquet2/block_iterator_test.go b/tempodb/encoding/vparquet2/block_iterator_test.go index 1463a0dfb17..cf2d80af4b0 100644 --- a/tempodb/encoding/vparquet2/block_iterator_test.go +++ b/tempodb/encoding/vparquet2/block_iterator_test.go @@ -32,7 +32,7 @@ func TestRawIteratorReadsAllRows(t *testing.T) { require.NoError(t, err) defer iter.Close() - actualCount := int32(0) + actualCount := int64(0) for { _, tr, err := iter.Next(context.Background()) if tr == nil { diff --git a/tempodb/encoding/vparquet2/compactor.go b/tempodb/encoding/vparquet2/compactor.go index ce4da0eda34..88e5a70686e 100644 --- a/tempodb/encoding/vparquet2/compactor.go +++ b/tempodb/encoding/vparquet2/compactor.go @@ -30,7 +30,7 @@ type Compactor struct { func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, w backend.Writer, inputs []*backend.BlockMeta) (newCompactedBlocks []*backend.BlockMeta, err error) { var ( compactionLevel uint32 - totalRecords int32 + totalRecords int64 minBlockStart time.Time maxBlockEnd time.Time bookmarks = make([]*bookmark[parquet.Row], 0, len(inputs)) @@ -126,7 +126,7 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, var ( m = newMultiblockIterator(bookmarks, combine) - recordsPerBlock = (totalRecords / int32(c.opts.OutputBlocks)) + recordsPerBlock = (totalRecords / int64(c.opts.OutputBlocks)) currentBlock *streamingBlock ) defer m.Close() diff --git a/tempodb/encoding/vparquet2/compactor_test.go b/tempodb/encoding/vparquet2/compactor_test.go index 02f236d2756..6cc6c7a2121 100644 --- a/tempodb/encoding/vparquet2/compactor_test.go +++ b/tempodb/encoding/vparquet2/compactor_test.go @@ -113,7 +113,7 @@ func createTestBlock(t testing.TB, ctx context.Context, cfg *common.BlockConfig, inMeta := &backend.BlockMeta{ TenantID: tenantID, BlockID: backend.NewUUID(), - TotalObjects: int32(traceCount), + TotalObjects: int64(traceCount), } sb := newStreamingBlock(ctx, cfg, inMeta, r, w, tempo_io.NewBufferedWriter) diff --git a/tempodb/encoding/vparquet3/block_findtracebyid_test.go b/tempodb/encoding/vparquet3/block_findtracebyid_test.go index ea8c40a265f..ebeaba20882 100644 --- a/tempodb/encoding/vparquet3/block_findtracebyid_test.go +++ b/tempodb/encoding/vparquet3/block_findtracebyid_test.go @@ -75,7 +75,7 @@ func TestBackendBlockFindTraceByID(t *testing.T) { }) meta := backend.NewBlockMeta("fake", uuid.New(), VersionString, backend.EncNone, "") - meta.TotalObjects = int32(len(traces)) + meta.TotalObjects = int64(len(traces)) s := newStreamingBlock(ctx, cfg, meta, r, w, tempo_io.NewBufferedWriter) // Write test data, occasionally flushing (cutting new row group) diff --git a/tempodb/encoding/vparquet3/block_iterator_test.go b/tempodb/encoding/vparquet3/block_iterator_test.go index 390c9871cb7..970c2494a03 100644 --- a/tempodb/encoding/vparquet3/block_iterator_test.go +++ b/tempodb/encoding/vparquet3/block_iterator_test.go @@ -32,7 +32,7 @@ func TestRawIteratorReadsAllRows(t *testing.T) { require.NoError(t, err) defer iter.Close() - actualCount := int32(0) + actualCount := int64(0) for { _, tr, err := iter.Next(context.Background()) if tr == nil { diff --git a/tempodb/encoding/vparquet3/compactor.go b/tempodb/encoding/vparquet3/compactor.go index 971d491bb19..19164617529 100644 --- a/tempodb/encoding/vparquet3/compactor.go +++ b/tempodb/encoding/vparquet3/compactor.go @@ -30,7 +30,7 @@ type Compactor struct { func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, w backend.Writer, inputs []*backend.BlockMeta) (newCompactedBlocks []*backend.BlockMeta, err error) { var ( compactionLevel uint32 - totalRecords int32 + totalRecords int64 minBlockStart time.Time maxBlockEnd time.Time bookmarks = make([]*bookmark[parquet.Row], 0, len(inputs)) @@ -132,7 +132,7 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, var ( m = newMultiblockIterator(bookmarks, combine) - recordsPerBlock = (totalRecords / int32(c.opts.OutputBlocks)) + recordsPerBlock = (totalRecords / int64(c.opts.OutputBlocks)) currentBlock *streamingBlock ) defer m.Close() diff --git a/tempodb/encoding/vparquet3/compactor_test.go b/tempodb/encoding/vparquet3/compactor_test.go index f5d8995c8b5..409a66ceba0 100644 --- a/tempodb/encoding/vparquet3/compactor_test.go +++ b/tempodb/encoding/vparquet3/compactor_test.go @@ -113,7 +113,7 @@ func createTestBlock(t testing.TB, ctx context.Context, cfg *common.BlockConfig, inMeta := &backend.BlockMeta{ TenantID: tenantID, BlockID: backend.NewUUID(), - TotalObjects: int32(traceCount), + TotalObjects: int64(traceCount), ReplicationFactor: uint32(replicationFactor), DedicatedColumns: dc, } @@ -209,7 +209,7 @@ func TestCompact(t *testing.T) { newMeta, err := c.Compact(context.Background(), log.NewNopLogger(), r, w, inputs) require.NoError(t, err) require.Len(t, newMeta, 1) - require.Equal(t, int32(20), newMeta[0].TotalObjects) + require.Equal(t, int64(20), newMeta[0].TotalObjects) require.Equal(t, uint32(1), newMeta[0].ReplicationFactor) require.Equal(t, dedicatedColumns, newMeta[0].DedicatedColumns) } diff --git a/tempodb/encoding/vparquet4/block_findtracebyid_test.go b/tempodb/encoding/vparquet4/block_findtracebyid_test.go index 5eceeb41d04..a5781840a16 100644 --- a/tempodb/encoding/vparquet4/block_findtracebyid_test.go +++ b/tempodb/encoding/vparquet4/block_findtracebyid_test.go @@ -75,7 +75,7 @@ func TestBackendBlockFindTraceByID(t *testing.T) { }) meta := backend.NewBlockMeta("fake", uuid.New(), VersionString, backend.EncNone, "") - meta.TotalObjects = int32(len(traces)) + meta.TotalObjects = int64(len(traces)) s := newStreamingBlock(ctx, cfg, meta, r, w, tempo_io.NewBufferedWriter) // Write test data, occasionally flushing (cutting new row group) diff --git a/tempodb/encoding/vparquet4/block_iterator_test.go b/tempodb/encoding/vparquet4/block_iterator_test.go index 2a501310919..ad5bbca1841 100644 --- a/tempodb/encoding/vparquet4/block_iterator_test.go +++ b/tempodb/encoding/vparquet4/block_iterator_test.go @@ -32,7 +32,7 @@ func TestRawIteratorReadsAllRows(t *testing.T) { require.NoError(t, err) defer iter.Close() - actualCount := int32(0) + actualCount := int64(0) for { _, tr, err := iter.Next(context.Background()) if tr == nil { diff --git a/tempodb/encoding/vparquet4/compactor.go b/tempodb/encoding/vparquet4/compactor.go index 3e72f20ea88..8cf64d08658 100644 --- a/tempodb/encoding/vparquet4/compactor.go +++ b/tempodb/encoding/vparquet4/compactor.go @@ -31,7 +31,7 @@ type Compactor struct { func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, w backend.Writer, inputs []*backend.BlockMeta) (newCompactedBlocks []*backend.BlockMeta, err error) { var ( compactionLevel uint32 - totalRecords int32 + totalRecords int64 minBlockStart time.Time maxBlockEnd time.Time bookmarks = make([]*bookmark[parquet.Row], 0, len(inputs)) @@ -133,7 +133,7 @@ func (c *Compactor) Compact(ctx context.Context, l log.Logger, r backend.Reader, var ( m = newMultiblockIterator(bookmarks, combine) - recordsPerBlock = (totalRecords / int32(c.opts.OutputBlocks)) + recordsPerBlock = (totalRecords / int64(c.opts.OutputBlocks)) currentBlock *streamingBlock ) defer m.Close() diff --git a/tempodb/encoding/vparquet4/compactor_test.go b/tempodb/encoding/vparquet4/compactor_test.go index aa811b6604a..b580b9c3b20 100644 --- a/tempodb/encoding/vparquet4/compactor_test.go +++ b/tempodb/encoding/vparquet4/compactor_test.go @@ -113,7 +113,7 @@ func createTestBlock(t testing.TB, ctx context.Context, cfg *common.BlockConfig, inMeta := &backend.BlockMeta{ TenantID: tenantID, BlockID: backend.NewUUID(), - TotalObjects: int32(traceCount), + TotalObjects: int64(traceCount), ReplicationFactor: uint32(replicationFactor), DedicatedColumns: dc, } @@ -209,7 +209,7 @@ func TestCompact(t *testing.T) { newMeta, err := c.Compact(context.Background(), log.NewNopLogger(), r, w, inputs) require.NoError(t, err) require.Len(t, newMeta, 1) - require.Equal(t, int32(20), newMeta[0].TotalObjects) + require.Equal(t, int64(20), newMeta[0].TotalObjects) require.Equal(t, uint32(1), newMeta[0].ReplicationFactor) require.Equal(t, dedicatedColumns, newMeta[0].DedicatedColumns) } From 379e83523db2ded1811d661a72c59510e6e8afce Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Mon, 30 Sep 2024 14:32:11 +0000 Subject: [PATCH 62/71] Store write buffer at object path in mocks to improve readability in tests --- tempodb/backend/mocks.go | 12 ++++++++---- tempodb/backend/raw_test.go | 18 ++++++++++++------ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/tempodb/backend/mocks.go b/tempodb/backend/mocks.go index 5b747fe6412..a77ba070b83 100644 --- a/tempodb/backend/mocks.go +++ b/tempodb/backend/mocks.go @@ -7,6 +7,7 @@ import ( "strings" "sync" + "github.com/davecgh/go-spew/spew" tempo_io "github.com/grafana/tempo/pkg/io" "github.com/google/uuid" @@ -72,20 +73,23 @@ func (m *MockRawReader) Shutdown() {} // MockRawWriter type MockRawWriter struct { - writeBuffer [][]byte + writeBuffer map[string][]byte appendBuffer []byte closeAppendCalled bool deleteCalls map[string]map[string]int err error } -func (m *MockRawWriter) Write(_ context.Context, _ string, _ KeyPath, data io.Reader, size int64, _ *CacheInfo) error { +func (m *MockRawWriter) Write(_ context.Context, object string, keypath KeyPath, data io.Reader, size int64, _ *CacheInfo) error { if m.writeBuffer == nil { - m.writeBuffer = make([][]byte, 0) + m.writeBuffer = make(map[string][]byte, 0) } + path := strings.Join(keypath, "/") + "/" + object + spew.Dump(path) + writeBuffer, err := tempo_io.ReadAllWithEstimate(data, size) - m.writeBuffer = append(m.writeBuffer, writeBuffer) + m.writeBuffer[path] = writeBuffer return err } diff --git a/tempodb/backend/raw_test.go b/tempodb/backend/raw_test.go index 04f9500b53c..0828f4f821d 100644 --- a/tempodb/backend/raw_test.go +++ b/tempodb/backend/raw_test.go @@ -3,6 +3,7 @@ package backend import ( "context" "encoding/json" + "path/filepath" "testing" "github.com/google/go-cmp/cmp" @@ -23,9 +24,10 @@ func TestWriter(t *testing.T) { expected := []byte{0x01, 0x02, 0x03, 0x04} - err := w.Write(ctx, "test", uuid.New(), "test", expected, nil) + u := uuid.New() + err := w.Write(ctx, "test", u, "test", expected, nil) assert.NoError(t, err) - assert.Equal(t, expected, m.writeBuffer[len(m.writeBuffer)-1]) + assert.Equal(t, expected, m.writeBuffer["test/"+u.String()+"/test"]) _, err = w.Append(ctx, "test", uuid.New(), "test", nil, expected) assert.NoError(t, err) @@ -35,7 +37,9 @@ func TestWriter(t *testing.T) { assert.NoError(t, err) assert.True(t, m.closeAppendCalled) - meta := NewBlockMeta("test", uuid.New(), "blerg", EncGZIP, "glarg") + u = uuid.New() + expectedPath := filepath.Join("test", u.String(), MetaName) + meta := NewBlockMeta("test", u, "blerg", EncGZIP, "glarg") jsonBytes, err := json.Marshal(meta) assert.NoError(t, err) assert.NoError(t, err) @@ -43,15 +47,17 @@ func TestWriter(t *testing.T) { // Write the block meta to the backend and validate the payloads. err = w.WriteBlockMeta(ctx, meta) assert.NoError(t, err) - assert.Equal(t, jsonBytes, m.writeBuffer[len(m.writeBuffer)-1]) + assert.Equal(t, jsonBytes, m.writeBuffer[expectedPath]) + tenantIndexPath := filepath.Join("test", TenantIndexName) + tenantIndexPathPb := filepath.Join("test", TenantIndexNamePb) // Write the tenant index to the backend and validate the payloads. err = w.WriteTenantIndex(ctx, "test", []*BlockMeta{meta}, nil) assert.NoError(t, err) // proto idxP := &TenantIndex{} - err = idxP.unmarshalPb(m.writeBuffer[len(m.writeBuffer)-2]) + err = idxP.unmarshalPb(m.writeBuffer[tenantIndexPathPb]) assert.NoError(t, err) assert.Equal(t, []*BlockMeta{meta}, idxP.Meta) @@ -60,7 +66,7 @@ func TestWriter(t *testing.T) { // json idxJ := &TenantIndex{} - err = idxJ.unmarshal(m.writeBuffer[len(m.writeBuffer)-1]) + err = idxJ.unmarshal(m.writeBuffer[tenantIndexPath]) assert.NoError(t, err) assert.Equal(t, []*BlockMeta{meta}, idxJ.Meta) From 838b9a4864bbff9b1416cc843a0ac53ef136fca2 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Mon, 30 Sep 2024 14:34:30 +0000 Subject: [PATCH 63/71] Avoid allocation in interface validation --- tempodb/backend/tenantindex.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tempodb/backend/tenantindex.go b/tempodb/backend/tenantindex.go index 7604c5b7cdb..dcebcde1acc 100644 --- a/tempodb/backend/tenantindex.go +++ b/tempodb/backend/tenantindex.go @@ -15,7 +15,7 @@ const ( internalFilename = "index.json" ) -var _ proto.Message = &TenantIndex{} +var _ proto.Message = (*TenantIndex)(nil) func newTenantIndex(meta []*BlockMeta, compactedMeta []*CompactedBlockMeta) *TenantIndex { return &TenantIndex{ From 9b0e40090d5f70c212d9802401d1831aede89533 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Mon, 30 Sep 2024 14:36:40 +0000 Subject: [PATCH 64/71] Update note to include intern --- tempodb/backend/block_meta.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tempodb/backend/block_meta.go b/tempodb/backend/block_meta.go index b0aa59f8717..b3da9f5da7e 100644 --- a/tempodb/backend/block_meta.go +++ b/tempodb/backend/block_meta.go @@ -309,8 +309,7 @@ func (dcs DedicatedColumns) Marshal() ([]byte, error) { return nil, nil } - // NOTE: This is a performance optimization to avoid re-unmarshalling the - // same data multiple times on the read. + // NOTE: The json bytes interned in a map to avoid re-unmarshalling the same byte slice. return json.Marshal(dcs) } @@ -329,8 +328,7 @@ func (dcs *DedicatedColumns) Unmarshal(data []byte) error { return nil } - // NOTE: See UnmarshalJSON for a performance optimization to record the json - // bytes for reuse. + // NOTE: The json bytes interned in a map to avoid re-unmarshalling the same byte slice. return json.Unmarshal(data, &dcs) } From a8fdddbca47edac60dd4c3634af1a265bbf317fe Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Mon, 30 Sep 2024 14:56:10 +0000 Subject: [PATCH 65/71] Pluralize metas and compacted_metas fields --- cmd/tempo-cli/cmd-migrate-tenant.go | 4 +- tempodb/backend/raw_test.go | 12 +- tempodb/backend/tenantindex.go | 6 +- tempodb/backend/tenantindex_benchmark_test.go | 16 +- tempodb/backend/tenantindex_test.go | 8 +- tempodb/backend/test/backend_test.go | 4 +- tempodb/backend/v1.pb.go | 144 +++++++++--------- tempodb/backend/v1/v1.proto | 4 +- tempodb/blocklist/poller.go | 8 +- 9 files changed, 103 insertions(+), 103 deletions(-) diff --git a/cmd/tempo-cli/cmd-migrate-tenant.go b/cmd/tempo-cli/cmd-migrate-tenant.go index e59874fe390..b527529719a 100644 --- a/cmd/tempo-cli/cmd-migrate-tenant.go +++ b/cmd/tempo-cli/cmd-migrate-tenant.go @@ -34,7 +34,7 @@ func (cmd *migrateTenantCmd) Run(opts *globalOptions) error { if err != nil { return fmt.Errorf("reading source tenant index: %w", err) } - fmt.Printf("Blocks in source: %d, compacted: %d\n", len(sourceTenantIndex.Meta), len(sourceTenantIndex.CompactedMeta)) + fmt.Printf("Blocks in source: %d, compacted: %d\n", len(sourceTenantIndex.Metas), len(sourceTenantIndex.CompactedMetas)) // TODO create dest directory if it doesn't exist yet? @@ -47,7 +47,7 @@ func (cmd *migrateTenantCmd) Run(opts *globalOptions) error { var copiedBlocks, copiedSize uint64 blocks: - for _, sourceBlockMeta := range sourceTenantIndex.Meta { + for _, sourceBlockMeta := range sourceTenantIndex.Metas { // check for collisions for _, uuidDest := range blocksDest { if (uuid.UUID)(sourceBlockMeta.BlockID) == uuidDest { diff --git a/tempodb/backend/raw_test.go b/tempodb/backend/raw_test.go index 0828f4f821d..31473425e95 100644 --- a/tempodb/backend/raw_test.go +++ b/tempodb/backend/raw_test.go @@ -60,18 +60,18 @@ func TestWriter(t *testing.T) { err = idxP.unmarshalPb(m.writeBuffer[tenantIndexPathPb]) assert.NoError(t, err) - assert.Equal(t, []*BlockMeta{meta}, idxP.Meta) - assert.True(t, cmp.Equal([]*BlockMeta{meta}, idxP.Meta)) // using cmp.Equal to compare json datetimes - assert.True(t, cmp.Equal([]*CompactedBlockMeta(nil), idxP.CompactedMeta)) // using cmp.Equal to compare json datetimes + assert.Equal(t, []*BlockMeta{meta}, idxP.Metas) + assert.True(t, cmp.Equal([]*BlockMeta{meta}, idxP.Metas)) // using cmp.Equal to compare json datetimes + assert.True(t, cmp.Equal([]*CompactedBlockMeta(nil), idxP.CompactedMetas)) // using cmp.Equal to compare json datetimes // json idxJ := &TenantIndex{} err = idxJ.unmarshal(m.writeBuffer[tenantIndexPath]) assert.NoError(t, err) - assert.Equal(t, []*BlockMeta{meta}, idxJ.Meta) - assert.True(t, cmp.Equal([]*BlockMeta{meta}, idxJ.Meta)) // using cmp.Equal to compare json datetimes - assert.True(t, cmp.Equal([]*CompactedBlockMeta(nil), idxJ.CompactedMeta)) // using cmp.Equal to compare json datetimes + assert.Equal(t, []*BlockMeta{meta}, idxJ.Metas) + assert.True(t, cmp.Equal([]*BlockMeta{meta}, idxJ.Metas)) // using cmp.Equal to compare json datetimes + assert.True(t, cmp.Equal([]*CompactedBlockMeta(nil), idxJ.CompactedMetas)) // using cmp.Equal to compare json datetimes // When there are no blocks, the tenant index should be deleted assert.Equal(t, map[string]map[string]int(nil), w.(*writer).w.(*MockRawWriter).deleteCalls) diff --git a/tempodb/backend/tenantindex.go b/tempodb/backend/tenantindex.go index dcebcde1acc..d877a9a7f90 100644 --- a/tempodb/backend/tenantindex.go +++ b/tempodb/backend/tenantindex.go @@ -19,9 +19,9 @@ var _ proto.Message = (*TenantIndex)(nil) func newTenantIndex(meta []*BlockMeta, compactedMeta []*CompactedBlockMeta) *TenantIndex { return &TenantIndex{ - CreatedAt: time.Now(), - Meta: meta, - CompactedMeta: compactedMeta, + CreatedAt: time.Now(), + Metas: meta, + CompactedMetas: compactedMeta, } } diff --git a/tempodb/backend/tenantindex_benchmark_test.go b/tempodb/backend/tenantindex_benchmark_test.go index 1a48d82caa5..4b9c9abee29 100644 --- a/tempodb/backend/tenantindex_benchmark_test.go +++ b/tempodb/backend/tenantindex_benchmark_test.go @@ -10,12 +10,12 @@ import ( func BenchmarkIndexMarshal(b *testing.B) { idx := &TenantIndex{ - Meta: []*BlockMeta{ + Metas: []*BlockMeta{ NewBlockMeta("test", uuid.New(), "v1", EncGZIP, "adsf"), NewBlockMeta("test", uuid.New(), "v2", EncNone, "adsf"), NewBlockMeta("test", uuid.New(), "v3", EncLZ4_4M, "adsf"), }, - CompactedMeta: []*CompactedBlockMeta{ + CompactedMetas: []*CompactedBlockMeta{ { BlockMeta: *NewBlockMeta("test", uuid.New(), "v1", EncGZIP, "adsf"), CompactedTime: time.Now(), @@ -31,8 +31,8 @@ func BenchmarkIndexMarshal(b *testing.B) { }, } - for i := range idx.Meta { - idx.Meta[i].DedicatedColumns = DedicatedColumns{ + for i := range idx.Metas { + idx.Metas[i].DedicatedColumns = DedicatedColumns{ {Scope: "resource", Name: "namespace", Type: "string"}, {Scope: "span", Name: "http.method", Type: "string"}, {Scope: "span", Name: "namespace", Type: "string"}, @@ -47,12 +47,12 @@ func BenchmarkIndexMarshal(b *testing.B) { func BenchmarkIndexUnmarshal(b *testing.B) { idx := &TenantIndex{ - Meta: []*BlockMeta{ + Metas: []*BlockMeta{ NewBlockMeta("test", uuid.New(), "v1", EncGZIP, "adsf"), NewBlockMeta("test", uuid.New(), "v2", EncNone, "adsf"), NewBlockMeta("test", uuid.New(), "v3", EncLZ4_4M, "adsf"), }, - CompactedMeta: []*CompactedBlockMeta{ + CompactedMetas: []*CompactedBlockMeta{ { BlockMeta: *NewBlockMeta("test", uuid.New(), "v1", EncGZIP, "adsf"), CompactedTime: time.Now(), @@ -68,8 +68,8 @@ func BenchmarkIndexUnmarshal(b *testing.B) { }, } - for i := range idx.Meta { - idx.Meta[i].DedicatedColumns = DedicatedColumns{ + for i := range idx.Metas { + idx.Metas[i].DedicatedColumns = DedicatedColumns{ {Scope: "resource", Name: "namespace", Type: "string"}, {Scope: "span", Name: "http.method", Type: "string"}, {Scope: "span", Name: "namespace", Type: "string"}, diff --git a/tempodb/backend/tenantindex_test.go b/tempodb/backend/tenantindex_test.go index 654c6ab5cbe..6d68e3fdad0 100644 --- a/tempodb/backend/tenantindex_test.go +++ b/tempodb/backend/tenantindex_test.go @@ -20,7 +20,7 @@ func TestIndexMarshalUnmarshal(t *testing.T) { { idx: &TenantIndex{ CreatedAt: time.Now(), - Meta: []*BlockMeta{ + Metas: []*BlockMeta{ NewBlockMeta("test", uuid.New(), "v1", EncGZIP, "adsf"), NewBlockMeta("test", uuid.New(), "v2", EncNone, "adsf"), NewBlockMeta("test", uuid.New(), "v3", EncLZ4_4M, "adsf"), @@ -30,7 +30,7 @@ func TestIndexMarshalUnmarshal(t *testing.T) { { idx: &TenantIndex{ CreatedAt: time.Now(), - CompactedMeta: []*CompactedBlockMeta{ + CompactedMetas: []*CompactedBlockMeta{ { BlockMeta: *NewBlockMeta("test", uuid.New(), "v1", EncGZIP, "adsf"), CompactedTime: time.Now(), @@ -48,12 +48,12 @@ func TestIndexMarshalUnmarshal(t *testing.T) { }, { idx: &TenantIndex{ - Meta: []*BlockMeta{ + Metas: []*BlockMeta{ NewBlockMeta("test", uuid.New(), "v1", EncGZIP, "adsf"), NewBlockMeta("test", uuid.New(), "v2", EncNone, "adsf"), NewBlockMeta("test", uuid.New(), "v3", EncLZ4_4M, "adsf"), }, - CompactedMeta: []*CompactedBlockMeta{ + CompactedMetas: []*CompactedBlockMeta{ { BlockMeta: *NewBlockMeta("test", uuid.New(), "v1", EncGZIP, "adsf"), CompactedTime: time.Now(), diff --git a/tempodb/backend/test/backend_test.go b/tempodb/backend/test/backend_test.go index f3f7143d549..f11d7f07010 100644 --- a/tempodb/backend/test/backend_test.go +++ b/tempodb/backend/test/backend_test.go @@ -84,8 +84,8 @@ func TestFixtures(t *testing.T) { var i *backend.TenantIndex i, err = r.TenantIndex(ctx, tenant) require.NoError(t, err) - require.Equal(t, blockMetas, i.Meta) - require.Len(t, i.Meta, len(listMetas)) + require.Equal(t, blockMetas, i.Metas) + require.Len(t, i.Metas, len(listMetas)) } func nonZeroMeta(t *testing.T, m []*backend.BlockMeta) { diff --git a/tempodb/backend/v1.pb.go b/tempodb/backend/v1.pb.go index 9646402569b..e06e99ff4f7 100644 --- a/tempodb/backend/v1.pb.go +++ b/tempodb/backend/v1.pb.go @@ -217,9 +217,9 @@ func (m *CompactedBlockMeta) GetCompactedTime() time.Time { } type TenantIndex struct { - CreatedAt time.Time `protobuf:"bytes,1,opt,name=created_at,json=createdAt,proto3,stdtime" json:"createdAt"` - Meta []*BlockMeta `protobuf:"bytes,2,rep,name=meta,proto3" json:"meta,omitempty"` - CompactedMeta []*CompactedBlockMeta `protobuf:"bytes,3,rep,name=compacted_meta,json=compactedMeta,proto3" json:"compacted_meta,omitempty"` + CreatedAt time.Time `protobuf:"bytes,1,opt,name=created_at,json=createdAt,proto3,stdtime" json:"createdAt"` + Metas []*BlockMeta `protobuf:"bytes,2,rep,name=metas,proto3" json:"metas,omitempty"` + CompactedMetas []*CompactedBlockMeta `protobuf:"bytes,3,rep,name=compacted_metas,json=compactedMetas,proto3" json:"compacted_metas,omitempty"` } func (m *TenantIndex) Reset() { *m = TenantIndex{} } @@ -262,16 +262,16 @@ func (m *TenantIndex) GetCreatedAt() time.Time { return time.Time{} } -func (m *TenantIndex) GetMeta() []*BlockMeta { +func (m *TenantIndex) GetMetas() []*BlockMeta { if m != nil { - return m.Meta + return m.Metas } return nil } -func (m *TenantIndex) GetCompactedMeta() []*CompactedBlockMeta { +func (m *TenantIndex) GetCompactedMetas() []*CompactedBlockMeta { if m != nil { - return m.CompactedMeta + return m.CompactedMetas } return nil } @@ -285,56 +285,56 @@ func init() { func init() { proto.RegisterFile("tempodb/backend/v1/v1.proto", fileDescriptor_6bc10ae735c1a340) } var fileDescriptor_6bc10ae735c1a340 = []byte{ - // 778 bytes of a gzipped FileDescriptorProto + // 784 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0xdd, 0x8a, 0xdb, 0x46, - 0x14, 0xb6, 0x76, 0xdd, 0xb5, 0x3d, 0xb6, 0xd7, 0xf6, 0x84, 0x80, 0xea, 0x80, 0xc7, 0x98, 0x5e, - 0x38, 0x90, 0xca, 0x6c, 0x4a, 0x0a, 0xa5, 0xb4, 0x50, 0xed, 0xa6, 0x90, 0xd2, 0x9f, 0xa0, 0x24, - 0x37, 0xa5, 0x20, 0x46, 0x9a, 0xb1, 0xa2, 0x46, 0xd2, 0x18, 0x69, 0x6c, 0xda, 0x3c, 0x45, 0x9e, - 0xa6, 0xcf, 0x10, 0x7a, 0xb5, 0xbd, 0x2b, 0xbd, 0x98, 0x16, 0xef, 0x9d, 0x9e, 0xa2, 0xcc, 0x91, - 0x2c, 0xd9, 0x5e, 0xca, 0xf6, 0xee, 0x9c, 0xf3, 0x9d, 0xef, 0xcc, 0x7c, 0x47, 0xf3, 0x09, 0x3d, - 0x90, 0x3c, 0x5e, 0x09, 0xe6, 0x2d, 0x3c, 0xea, 0xbf, 0xe1, 0x09, 0x5b, 0x6c, 0x2e, 0x16, 0x9b, - 0x0b, 0x6b, 0x95, 0x0a, 0x29, 0x30, 0x2a, 0x8b, 0xd6, 0xe6, 0x62, 0x4c, 0x02, 0x21, 0x82, 0x88, - 0x2f, 0x00, 0xf1, 0xd6, 0xcb, 0x85, 0x0c, 0x63, 0x9e, 0x49, 0x1a, 0xaf, 0x8a, 0xe6, 0xf1, 0xc7, - 0x41, 0x28, 0x5f, 0xaf, 0x3d, 0xcb, 0x17, 0xf1, 0x22, 0x10, 0x81, 0xa8, 0x3b, 0x75, 0x06, 0x09, - 0x44, 0x45, 0xfb, 0xec, 0xf7, 0x16, 0xea, 0xd8, 0x91, 0xf0, 0xdf, 0x7c, 0xc7, 0x25, 0xc5, 0x1f, - 0xa1, 0xd6, 0x86, 0xa7, 0x59, 0x28, 0x12, 0xd3, 0x98, 0x1a, 0xf3, 0x8e, 0x8d, 0x72, 0x45, 0xce, - 0x96, 0x22, 0x8d, 0xa9, 0x74, 0x76, 0x10, 0xfe, 0x02, 0xb5, 0x3d, 0x4d, 0x71, 0x43, 0x66, 0x9e, - 0x4c, 0x8d, 0x79, 0xcf, 0x9e, 0xbd, 0x57, 0xa4, 0xf1, 0x97, 0x22, 0xcd, 0x57, 0xaf, 0x9e, 0x5d, - 0x6d, 0x15, 0x69, 0xc1, 0xc8, 0x67, 0x57, 0xb9, 0x22, 0x2d, 0xaf, 0x08, 0x9d, 0x32, 0x60, 0xf8, - 0x09, 0xea, 0x48, 0x9e, 0xd0, 0x44, 0x6a, 0xfe, 0x07, 0x70, 0x8c, 0xb9, 0x55, 0xa4, 0xfd, 0x12, - 0x8a, 0x40, 0x6a, 0xcb, 0x32, 0x76, 0x76, 0x11, 0xc3, 0xcf, 0x11, 0xca, 0x24, 0x4d, 0xa5, 0xab, - 0x15, 0x9b, 0x67, 0x53, 0x63, 0xde, 0x7d, 0x3c, 0xb6, 0x8a, 0x75, 0x58, 0x3b, 0x91, 0xd6, 0xcb, - 0xdd, 0x3a, 0xec, 0xfb, 0xfa, 0x4e, 0xb9, 0x22, 0x1d, 0x60, 0xe9, 0xfa, 0xbb, 0xbf, 0x89, 0xe1, - 0xd4, 0x29, 0xfe, 0x06, 0xb5, 0x79, 0xc2, 0x8a, 0x79, 0xad, 0x3b, 0xe7, 0xdd, 0x2b, 0xe7, 0xb5, - 0x78, 0xc2, 0xaa, 0x69, 0xbb, 0x04, 0x3f, 0x41, 0x7d, 0x29, 0x24, 0x8d, 0x5c, 0xe1, 0xfd, 0xcc, - 0x7d, 0x99, 0x99, 0xed, 0xa9, 0x31, 0x3f, 0xb5, 0x87, 0xb9, 0x22, 0x3d, 0x00, 0x7e, 0x28, 0xea, - 0xce, 0x41, 0x86, 0x31, 0x6a, 0x66, 0xe1, 0x5b, 0x6e, 0x76, 0xa6, 0xc6, 0xbc, 0xe9, 0x40, 0x8c, - 0xbf, 0x44, 0x43, 0x5f, 0xc4, 0x2b, 0xea, 0xcb, 0x50, 0x24, 0x6e, 0xc4, 0x37, 0x3c, 0x32, 0xd1, - 0xd4, 0x98, 0xf7, 0xed, 0x7b, 0xb9, 0x22, 0x83, 0x1a, 0xfb, 0x56, 0x43, 0xce, 0x71, 0x01, 0x3f, - 0xd2, 0xb2, 0x7c, 0xc1, 0xc2, 0x24, 0x30, 0xbb, 0xf0, 0x79, 0x86, 0xe5, 0xe7, 0x69, 0x3f, 0x2d, - 0xeb, 0x4e, 0xd5, 0x81, 0x3f, 0x43, 0x83, 0x30, 0x61, 0xfc, 0x17, 0x77, 0x45, 0x03, 0xee, 0xc2, - 0x65, 0x7a, 0x70, 0xd8, 0x28, 0x57, 0xa4, 0x0f, 0xd0, 0x73, 0x1a, 0xf0, 0x17, 0xe1, 0x5b, 0xee, - 0x1c, 0xa6, 0xb5, 0xe6, 0x94, 0xfb, 0x22, 0x65, 0x99, 0xd9, 0x07, 0x62, 0xad, 0xd9, 0x29, 0xea, - 0xce, 0x41, 0xa6, 0x69, 0x8c, 0x4a, 0xea, 0x56, 0x97, 0x3c, 0x87, 0x37, 0x00, 0x34, 0x0d, 0x54, - 0x97, 0x3c, 0xc8, 0xf0, 0xe7, 0x68, 0xe4, 0x45, 0x42, 0xc4, 0x6e, 0xf6, 0x9a, 0xa6, 0xcc, 0xf5, - 0xc5, 0x3a, 0x91, 0xe6, 0x00, 0x4e, 0x1c, 0xe4, 0x8a, 0x74, 0x01, 0x7c, 0xa1, 0xb1, 0xcc, 0x19, - 0xd4, 0xc9, 0xa5, 0xee, 0xc3, 0x0b, 0xd4, 0x5d, 0x0a, 0x21, 0x79, 0x5a, 0x28, 0x1c, 0x02, 0xed, - 0x3c, 0x57, 0x04, 0x15, 0x65, 0x90, 0xb7, 0x17, 0x63, 0x1f, 0x8d, 0x18, 0x67, 0xa1, 0x4f, 0x25, - 0xd7, 0x67, 0x45, 0xeb, 0x38, 0xc9, 0xcc, 0x11, 0x6c, 0xf3, 0xd3, 0x72, 0x9b, 0xc3, 0xab, 0x5d, - 0xc3, 0x65, 0x81, 0xe7, 0x8a, 0x8c, 0xd9, 0x51, 0xed, 0x91, 0x88, 0x43, 0xed, 0x6d, 0xf9, 0xab, - 0x33, 0x3c, 0xc6, 0xf0, 0xf7, 0x08, 0xa7, 0x7c, 0x15, 0xe9, 0xa2, 0xfe, 0xd4, 0x4b, 0xea, 0x4b, - 0x91, 0x9a, 0x18, 0x2e, 0x47, 0x72, 0x45, 0x1e, 0xec, 0xa1, 0x5f, 0x03, 0xb8, 0x37, 0x6e, 0x74, - 0x0b, 0x9c, 0xfd, 0x66, 0x20, 0x7c, 0x59, 0xbc, 0x06, 0xce, 0x6a, 0x57, 0xdb, 0x08, 0x15, 0x7e, - 0x8d, 0xb9, 0xa4, 0x60, 0xec, 0xee, 0xe3, 0xfb, 0x56, 0xfd, 0x53, 0xb1, 0xaa, 0x56, 0xbb, 0xa7, - 0xb5, 0x5d, 0x2b, 0x62, 0xe4, 0x8a, 0x34, 0x9c, 0x8e, 0x57, 0xcd, 0xf8, 0x09, 0x9d, 0xfb, 0xbb, - 0xc9, 0x85, 0x63, 0x4e, 0xee, 0x74, 0xcc, 0x87, 0xa5, 0x63, 0xfa, 0x15, 0xb3, 0xf2, 0xcd, 0x61, - 0x69, 0xf6, 0x87, 0x81, 0xba, 0xa5, 0xfd, 0xf5, 0x0b, 0xd3, 0x5e, 0xf7, 0x53, 0x0e, 0xbb, 0xa7, - 0xb2, 0xbc, 0xf1, 0xff, 0xf2, 0x7a, 0xc9, 0xfa, 0x4a, 0x16, 0x5e, 0xaf, 0x52, 0xfc, 0x10, 0x35, - 0x41, 0xfd, 0xc9, 0xf4, 0xf4, 0x3f, 0xd5, 0x3b, 0xd0, 0x82, 0x9f, 0xee, 0x4b, 0x05, 0xd2, 0x29, - 0x90, 0x26, 0xfb, 0xa4, 0xdb, 0x6b, 0xde, 0xd3, 0x04, 0xab, 0x7c, 0xf8, 0x7e, 0x3b, 0x31, 0xae, - 0xb7, 0x13, 0xe3, 0x9f, 0xed, 0xc4, 0x78, 0x77, 0x33, 0x69, 0x5c, 0xdf, 0x4c, 0x1a, 0x7f, 0xde, - 0x4c, 0x1a, 0x3f, 0x0e, 0x8e, 0x7e, 0xf6, 0xde, 0x19, 0x48, 0xfa, 0xe4, 0xdf, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xfe, 0x92, 0x00, 0xfe, 0x06, 0x06, 0x00, 0x00, + 0x14, 0xb6, 0x76, 0x37, 0x6b, 0x7b, 0x6c, 0xaf, 0xed, 0x09, 0x01, 0xd5, 0x01, 0x8f, 0x31, 0xbd, + 0x70, 0x69, 0x2a, 0xb3, 0x29, 0x29, 0x94, 0xd2, 0x42, 0xb5, 0xdb, 0x96, 0x94, 0xfe, 0x84, 0x49, + 0x72, 0x53, 0x0a, 0x62, 0xa4, 0x19, 0x2b, 0x6a, 0x24, 0x8d, 0x91, 0xc6, 0xa6, 0xcd, 0x53, 0xe4, + 0x69, 0xfa, 0x0c, 0x4b, 0xaf, 0xf6, 0xa6, 0x50, 0x7a, 0x31, 0x2d, 0xde, 0x3b, 0x3d, 0x45, 0x99, + 0x19, 0x59, 0xb2, 0xbd, 0x94, 0xcd, 0xdd, 0x39, 0xe7, 0x3b, 0xdf, 0x99, 0xf9, 0x8e, 0xe6, 0x13, + 0x78, 0x28, 0x58, 0xb2, 0xe4, 0xd4, 0x9f, 0xfb, 0x24, 0x78, 0xcd, 0x52, 0x3a, 0x5f, 0x9f, 0xcf, + 0xd7, 0xe7, 0xce, 0x32, 0xe3, 0x82, 0x43, 0x50, 0x16, 0x9d, 0xf5, 0xf9, 0x08, 0x85, 0x9c, 0x87, + 0x31, 0x9b, 0x6b, 0xc4, 0x5f, 0x2d, 0xe6, 0x22, 0x4a, 0x58, 0x2e, 0x48, 0xb2, 0x34, 0xcd, 0xa3, + 0x8f, 0xc2, 0x48, 0xbc, 0x5a, 0xf9, 0x4e, 0xc0, 0x93, 0x79, 0xc8, 0x43, 0x5e, 0x77, 0xaa, 0x4c, + 0x27, 0x3a, 0x32, 0xed, 0xd3, 0x3f, 0x9a, 0xa0, 0xed, 0xc6, 0x3c, 0x78, 0xfd, 0x3d, 0x13, 0x04, + 0xbe, 0x0f, 0x9a, 0x6b, 0x96, 0xe5, 0x11, 0x4f, 0x6d, 0x6b, 0x62, 0xcd, 0xda, 0x2e, 0x28, 0x24, + 0x3a, 0x5d, 0xf0, 0x2c, 0x21, 0x02, 0x6f, 0x21, 0xf8, 0x39, 0x68, 0xf9, 0x8a, 0xe2, 0x45, 0xd4, + 0x3e, 0x9a, 0x58, 0xb3, 0xae, 0x3b, 0xbd, 0x92, 0xa8, 0xf1, 0xb7, 0x44, 0x27, 0x2f, 0x5f, 0x3e, + 0xbd, 0xdc, 0x48, 0xd4, 0xd4, 0x23, 0x9f, 0x5e, 0x16, 0x12, 0x35, 0x7d, 0x13, 0xe2, 0x32, 0xa0, + 0xf0, 0x09, 0x68, 0x0b, 0x96, 0x92, 0x54, 0x28, 0xfe, 0x3d, 0x7d, 0x8c, 0xbd, 0x91, 0xa8, 0xf5, + 0x42, 0x17, 0x35, 0xa9, 0x25, 0xca, 0x18, 0x6f, 0x23, 0x0a, 0x9f, 0x01, 0x90, 0x0b, 0x92, 0x09, + 0x4f, 0x29, 0xb6, 0x4f, 0x27, 0xd6, 0xac, 0xf3, 0x78, 0xe4, 0x98, 0x75, 0x38, 0x5b, 0x91, 0xce, + 0x8b, 0xed, 0x3a, 0xdc, 0x07, 0xea, 0x4e, 0x85, 0x44, 0x6d, 0xcd, 0x52, 0xf5, 0xb7, 0xff, 0x20, + 0x0b, 0xd7, 0x29, 0xfc, 0x16, 0xb4, 0x58, 0x4a, 0xcd, 0xbc, 0xe6, 0x9d, 0xf3, 0xee, 0x97, 0xf3, + 0x9a, 0x2c, 0xa5, 0xd5, 0xb4, 0x6d, 0x02, 0x9f, 0x80, 0x9e, 0xe0, 0x82, 0xc4, 0x1e, 0xf7, 0x7f, + 0x61, 0x81, 0xc8, 0xed, 0xd6, 0xc4, 0x9a, 0x1d, 0xbb, 0x83, 0x42, 0xa2, 0xae, 0x06, 0x7e, 0x34, + 0x75, 0xbc, 0x97, 0x41, 0x08, 0x4e, 0xf2, 0xe8, 0x0d, 0xb3, 0xdb, 0x13, 0x6b, 0x76, 0x82, 0x75, + 0x0c, 0xbf, 0x00, 0x83, 0x80, 0x27, 0x4b, 0x12, 0x88, 0x88, 0xa7, 0x5e, 0xcc, 0xd6, 0x2c, 0xb6, + 0xc1, 0xc4, 0x9a, 0xf5, 0xdc, 0xfb, 0x85, 0x44, 0xfd, 0x1a, 0xfb, 0x4e, 0x41, 0xf8, 0xb0, 0x00, + 0x1f, 0x29, 0x59, 0x01, 0xa7, 0x51, 0x1a, 0xda, 0x1d, 0xfd, 0x79, 0x06, 0xe5, 0xe7, 0x69, 0x7d, + 0x55, 0xd6, 0x71, 0xd5, 0x01, 0x3f, 0x05, 0xfd, 0x28, 0xa5, 0xec, 0x57, 0x6f, 0x49, 0x42, 0xe6, + 0xe9, 0xcb, 0x74, 0xf5, 0x61, 0xc3, 0x42, 0xa2, 0x9e, 0x86, 0x9e, 0x91, 0x90, 0x3d, 0x8f, 0xde, + 0x30, 0xbc, 0x9f, 0xd6, 0x9a, 0x33, 0x16, 0xf0, 0x8c, 0xe6, 0x76, 0x4f, 0x13, 0x6b, 0xcd, 0xd8, + 0xd4, 0xf1, 0x5e, 0xa6, 0x68, 0x94, 0x08, 0xe2, 0x55, 0x97, 0x3c, 0xd3, 0x6f, 0x40, 0xd3, 0x14, + 0x50, 0x5d, 0x72, 0x2f, 0x83, 0x9f, 0x81, 0xa1, 0x1f, 0x73, 0x9e, 0x78, 0xf9, 0x2b, 0x92, 0x51, + 0x2f, 0xe0, 0xab, 0x54, 0xd8, 0x7d, 0x7d, 0x62, 0xbf, 0x90, 0xa8, 0xa3, 0xc1, 0xe7, 0x0a, 0xcb, + 0x71, 0xbf, 0x4e, 0x2e, 0x54, 0x1f, 0x9c, 0x83, 0xce, 0x82, 0x73, 0xc1, 0x32, 0xa3, 0x70, 0xa0, + 0x69, 0x67, 0x85, 0x44, 0xc0, 0x94, 0xb5, 0xbc, 0x9d, 0x18, 0x06, 0x60, 0x48, 0x19, 0x8d, 0x02, + 0x22, 0x98, 0x3a, 0x2b, 0x5e, 0x25, 0x69, 0x6e, 0x0f, 0xf5, 0x36, 0x3f, 0x29, 0xb7, 0x39, 0xb8, + 0xdc, 0x36, 0x5c, 0x18, 0xbc, 0x90, 0x68, 0x44, 0x0f, 0x6a, 0x8f, 0x78, 0x12, 0x29, 0x6f, 0x8b, + 0xdf, 0xf0, 0xe0, 0x10, 0x83, 0x3f, 0x00, 0x98, 0xb1, 0x65, 0xac, 0x8a, 0xea, 0x53, 0x2f, 0x48, + 0x20, 0x78, 0x66, 0x43, 0x7d, 0x39, 0x54, 0x48, 0xf4, 0x70, 0x07, 0xfd, 0x5a, 0x83, 0x3b, 0xe3, + 0x86, 0xb7, 0xc0, 0xe9, 0xef, 0x16, 0x80, 0x17, 0xe6, 0x35, 0x30, 0x5a, 0xbb, 0xda, 0x05, 0xc0, + 0xf8, 0x35, 0x61, 0x82, 0x68, 0x63, 0x77, 0x1e, 0x3f, 0x70, 0xea, 0x9f, 0x8a, 0x53, 0xb5, 0xba, + 0x5d, 0xa5, 0xed, 0x5a, 0x22, 0xab, 0x90, 0xa8, 0x81, 0xdb, 0x7e, 0x35, 0xe3, 0x67, 0x70, 0x16, + 0x6c, 0x27, 0x1b, 0xc7, 0x1c, 0xdd, 0xe9, 0x98, 0xf7, 0x4a, 0xc7, 0xf4, 0x2a, 0x66, 0xe5, 0x9b, + 0xfd, 0xd2, 0xf4, 0x4f, 0x0b, 0x74, 0x4a, 0xfb, 0xab, 0x17, 0xa6, 0xbc, 0x1e, 0x64, 0x4c, 0xef, + 0x9e, 0x88, 0xf2, 0xc6, 0xef, 0xe4, 0xf5, 0x92, 0xf5, 0xa5, 0x30, 0x5e, 0xaf, 0x52, 0xf8, 0x21, + 0xb8, 0xa7, 0xd4, 0xe7, 0xf6, 0xd1, 0xe4, 0xf8, 0x7f, 0xe5, 0x63, 0xd3, 0x03, 0xbf, 0x01, 0xfd, + 0x5a, 0xac, 0xa1, 0x1d, 0x6b, 0xda, 0x78, 0x97, 0x76, 0x7b, 0xd3, 0xb8, 0xde, 0x91, 0x4a, 0x73, + 0xf7, 0x83, 0xab, 0xcd, 0xd8, 0xba, 0xde, 0x8c, 0xad, 0x7f, 0x37, 0x63, 0xeb, 0xed, 0xcd, 0xb8, + 0x71, 0x7d, 0x33, 0x6e, 0xfc, 0x75, 0x33, 0x6e, 0xfc, 0xd4, 0x3f, 0xf8, 0xe1, 0xfb, 0xa7, 0x5a, + 0xd6, 0xc7, 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0x8e, 0xd1, 0x6d, 0x86, 0x0a, 0x06, 0x00, 0x00, } func (m *BlockMeta) Marshal() (dAtA []byte, err error) { @@ -534,10 +534,10 @@ func (m *TenantIndex) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.CompactedMeta) > 0 { - for iNdEx := len(m.CompactedMeta) - 1; iNdEx >= 0; iNdEx-- { + if len(m.CompactedMetas) > 0 { + for iNdEx := len(m.CompactedMetas) - 1; iNdEx >= 0; iNdEx-- { { - size, err := m.CompactedMeta[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + size, err := m.CompactedMetas[iNdEx].MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -548,10 +548,10 @@ func (m *TenantIndex) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x1a } } - if len(m.Meta) > 0 { - for iNdEx := len(m.Meta) - 1; iNdEx >= 0; iNdEx-- { + if len(m.Metas) > 0 { + for iNdEx := len(m.Metas) - 1; iNdEx >= 0; iNdEx-- { { - size, err := m.Meta[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + size, err := m.Metas[iNdEx].MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -660,14 +660,14 @@ func (m *TenantIndex) Size() (n int) { _ = l l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt) n += 1 + l + sovV1(uint64(l)) - if len(m.Meta) > 0 { - for _, e := range m.Meta { + if len(m.Metas) > 0 { + for _, e := range m.Metas { l = e.Size() n += 1 + l + sovV1(uint64(l)) } } - if len(m.CompactedMeta) > 0 { - for _, e := range m.CompactedMeta { + if len(m.CompactedMetas) > 0 { + for _, e := range m.CompactedMetas { l = e.Size() n += 1 + l + sovV1(uint64(l)) } @@ -1324,7 +1324,7 @@ func (m *TenantIndex) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Meta", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Metas", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1351,14 +1351,14 @@ func (m *TenantIndex) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Meta = append(m.Meta, &BlockMeta{}) - if err := m.Meta[len(m.Meta)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.Metas = append(m.Metas, &BlockMeta{}) + if err := m.Metas[len(m.Metas)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CompactedMeta", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field CompactedMetas", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1385,8 +1385,8 @@ func (m *TenantIndex) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.CompactedMeta = append(m.CompactedMeta, &CompactedBlockMeta{}) - if err := m.CompactedMeta[len(m.CompactedMeta)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.CompactedMetas = append(m.CompactedMetas, &CompactedBlockMeta{}) + if err := m.CompactedMetas[len(m.CompactedMetas)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/tempodb/backend/v1/v1.proto b/tempodb/backend/v1/v1.proto index b6617f1c8f6..7a9e319663f 100644 --- a/tempodb/backend/v1/v1.proto +++ b/tempodb/backend/v1/v1.proto @@ -34,6 +34,6 @@ message CompactedBlockMeta { message TenantIndex { google.protobuf.Timestamp created_at = 1[(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = "createdAt"]; - repeated BlockMeta meta = 2; - repeated CompactedBlockMeta compacted_meta = 3; + repeated BlockMeta metas = 2; + repeated CompactedBlockMeta compacted_metas = 3; } diff --git a/tempodb/blocklist/poller.go b/tempodb/blocklist/poller.go index e2fc1ed2751..d14d9c0e9a8 100644 --- a/tempodb/blocklist/poller.go +++ b/tempodb/blocklist/poller.go @@ -256,11 +256,11 @@ func (p *Poller) pollTenantAndCreateIndex( if err == nil { // success! return the retrieved index metricTenantIndexAgeSeconds.WithLabelValues(tenantID).Set(float64(time.Since(i.CreatedAt) / time.Second)) - level.Info(p.logger).Log("msg", "successfully pulled tenant index", "tenant", tenantID, "createdAt", i.CreatedAt, "metas", len(i.Meta), "compactedMetas", len(i.CompactedMeta)) + level.Info(p.logger).Log("msg", "successfully pulled tenant index", "tenant", tenantID, "createdAt", i.CreatedAt, "metas", len(i.Metas), "compactedMetas", len(i.CompactedMetas)) - span.SetAttributes(attribute.Int("metas", len(i.Meta))) - span.SetAttributes(attribute.Int("compactedMetas", len(i.CompactedMeta))) - return i.Meta, i.CompactedMeta, nil + span.SetAttributes(attribute.Int("metas", len(i.Metas))) + span.SetAttributes(attribute.Int("compactedMetas", len(i.CompactedMetas))) + return i.Metas, i.CompactedMetas, nil } metricTenantIndexErrors.WithLabelValues(tenantID).Inc() From 8a2dfd9f57ac761a82b1b05c66d6eb6b35cd18a6 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Mon, 30 Sep 2024 16:39:11 +0000 Subject: [PATCH 66/71] Fallback to json only on ErrDoesNotExist --- tempodb/backend/raw.go | 4 +++ tempodb/backend/raw_test.go | 57 +++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/tempodb/backend/raw.go b/tempodb/backend/raw.go index a3c68ef034b..689eebf3c31 100644 --- a/tempodb/backend/raw.go +++ b/tempodb/backend/raw.go @@ -251,6 +251,10 @@ func (r *reader) TenantIndex(ctx context.Context, tenantID string) (*TenantIndex return outPb, nil } + if !errors.Is(err, ErrDoesNotExist) { + return nil, err + } + span.AddEvent(EventJSONFallback) readerJ, size, err := r.r.Read(ctx, TenantIndexName, KeyPath([]string{tenantID}), nil) diff --git a/tempodb/backend/raw_test.go b/tempodb/backend/raw_test.go index 31473425e95..46109c6fd22 100644 --- a/tempodb/backend/raw_test.go +++ b/tempodb/backend/raw_test.go @@ -1,8 +1,11 @@ package backend import ( + "bytes" "context" "encoding/json" + "fmt" + "io" "path/filepath" "testing" @@ -236,3 +239,57 @@ func TestRoundTripMeta(t *testing.T) { assert.NoError(t, err) assert.Equal(t, meta, expected2) } + +func TestTenantIndexFallback(t *testing.T) { + var ( + mr = &MockRawReader{} + r = NewReader(mr) + mw = &MockRawWriter{} + w = NewWriter(mw) + ctx = context.Background() + tenantID = "test" + + u = uuid.New() + meta = NewBlockMeta(tenantID, u, "blerg", EncGZIP, "glarg") + expectedIdx = newTenantIndex([]*BlockMeta{meta}, nil) + ) + + err := w.WriteTenantIndex(ctx, tenantID, []*BlockMeta{meta}, nil) + assert.NoError(t, err) + + mr.R, err = expectedIdx.marshal() + assert.NoError(t, err) + mr.ReadFn = func(_ context.Context, name string, _ KeyPath, _ *CacheInfo) (io.ReadCloser, int64, error) { + if name == TenantIndexNamePb { + return nil, 0, fmt.Errorf("meow: %w", ErrDoesNotExist) + } + + return io.NopCloser(bytes.NewReader(mr.R)), int64(len(mr.R)), nil + } + + idx, err := r.TenantIndex(ctx, tenantID) + assert.NoError(t, err) + assert.True(t, cmp.Equal(expectedIdx, idx)) + + // Corrupt the proto to ensure we don't fall back + mr.ReadFn = func(_ context.Context, name string, _ KeyPath, _ *CacheInfo) (io.ReadCloser, int64, error) { + if name == TenantIndexNamePb { + return io.NopCloser(bytes.NewReader([]byte{0x00})), int64(1), nil + } + + return io.NopCloser(bytes.NewReader(mr.R)), int64(len(mr.R)), nil + } + + idx, err = r.TenantIndex(ctx, tenantID) + assert.ErrorIs(t, err, io.ErrUnexpectedEOF) + assert.Nil(t, idx) + + // Remove all indexes and error check + mr.ReadFn = func(_ context.Context, name string, _ KeyPath, _ *CacheInfo) (io.ReadCloser, int64, error) { + return nil, 0, fmt.Errorf("meow: %w", ErrDoesNotExist) + } + + idx, err = r.TenantIndex(ctx, tenantID) + assert.ErrorIs(t, err, ErrDoesNotExist) + assert.Nil(t, idx) +} From 8de8a5eac168a6beef730c1f10456b4c1229ba70 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Mon, 30 Sep 2024 18:53:35 +0000 Subject: [PATCH 67/71] Lint --- tempodb/backend/raw_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tempodb/backend/raw_test.go b/tempodb/backend/raw_test.go index 46109c6fd22..9c6a5211eaf 100644 --- a/tempodb/backend/raw_test.go +++ b/tempodb/backend/raw_test.go @@ -285,7 +285,7 @@ func TestTenantIndexFallback(t *testing.T) { assert.Nil(t, idx) // Remove all indexes and error check - mr.ReadFn = func(_ context.Context, name string, _ KeyPath, _ *CacheInfo) (io.ReadCloser, int64, error) { + mr.ReadFn = func(_ context.Context, _ string, _ KeyPath, _ *CacheInfo) (io.ReadCloser, int64, error) { return nil, 0, fmt.Errorf("meow: %w", ErrDoesNotExist) } From 3ae8611bafa09664b25e2db5acf5491638df4724 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Mon, 30 Sep 2024 18:54:38 +0000 Subject: [PATCH 68/71] Drop debug --- tempodb/backend/mocks.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/tempodb/backend/mocks.go b/tempodb/backend/mocks.go index a77ba070b83..cba366ae883 100644 --- a/tempodb/backend/mocks.go +++ b/tempodb/backend/mocks.go @@ -7,7 +7,6 @@ import ( "strings" "sync" - "github.com/davecgh/go-spew/spew" tempo_io "github.com/grafana/tempo/pkg/io" "github.com/google/uuid" @@ -86,7 +85,6 @@ func (m *MockRawWriter) Write(_ context.Context, object string, keypath KeyPath, } path := strings.Join(keypath, "/") + "/" + object - spew.Dump(path) writeBuffer, err := tempo_io.ReadAllWithEstimate(data, size) m.writeBuffer[path] = writeBuffer From 1216d7db8c5486b5825f7305c7aad41f87ead3cc Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Tue, 1 Oct 2024 14:42:10 +0000 Subject: [PATCH 69/71] Revert "Pluralize metas and compacted_metas fields" This reverts commit 46a8c36e37ac33e1ffc104287d898930e02cdd97. --- cmd/tempo-cli/cmd-migrate-tenant.go | 4 +- tempodb/backend/raw_test.go | 12 +- tempodb/backend/tenantindex.go | 6 +- tempodb/backend/tenantindex_benchmark_test.go | 16 +- tempodb/backend/tenantindex_test.go | 8 +- tempodb/backend/test/backend_test.go | 4 +- tempodb/backend/v1.pb.go | 144 +++++++++--------- tempodb/backend/v1/v1.proto | 4 +- tempodb/blocklist/poller.go | 8 +- 9 files changed, 103 insertions(+), 103 deletions(-) diff --git a/cmd/tempo-cli/cmd-migrate-tenant.go b/cmd/tempo-cli/cmd-migrate-tenant.go index b527529719a..e59874fe390 100644 --- a/cmd/tempo-cli/cmd-migrate-tenant.go +++ b/cmd/tempo-cli/cmd-migrate-tenant.go @@ -34,7 +34,7 @@ func (cmd *migrateTenantCmd) Run(opts *globalOptions) error { if err != nil { return fmt.Errorf("reading source tenant index: %w", err) } - fmt.Printf("Blocks in source: %d, compacted: %d\n", len(sourceTenantIndex.Metas), len(sourceTenantIndex.CompactedMetas)) + fmt.Printf("Blocks in source: %d, compacted: %d\n", len(sourceTenantIndex.Meta), len(sourceTenantIndex.CompactedMeta)) // TODO create dest directory if it doesn't exist yet? @@ -47,7 +47,7 @@ func (cmd *migrateTenantCmd) Run(opts *globalOptions) error { var copiedBlocks, copiedSize uint64 blocks: - for _, sourceBlockMeta := range sourceTenantIndex.Metas { + for _, sourceBlockMeta := range sourceTenantIndex.Meta { // check for collisions for _, uuidDest := range blocksDest { if (uuid.UUID)(sourceBlockMeta.BlockID) == uuidDest { diff --git a/tempodb/backend/raw_test.go b/tempodb/backend/raw_test.go index 9c6a5211eaf..a6bace3221c 100644 --- a/tempodb/backend/raw_test.go +++ b/tempodb/backend/raw_test.go @@ -63,18 +63,18 @@ func TestWriter(t *testing.T) { err = idxP.unmarshalPb(m.writeBuffer[tenantIndexPathPb]) assert.NoError(t, err) - assert.Equal(t, []*BlockMeta{meta}, idxP.Metas) - assert.True(t, cmp.Equal([]*BlockMeta{meta}, idxP.Metas)) // using cmp.Equal to compare json datetimes - assert.True(t, cmp.Equal([]*CompactedBlockMeta(nil), idxP.CompactedMetas)) // using cmp.Equal to compare json datetimes + assert.Equal(t, []*BlockMeta{meta}, idxP.Meta) + assert.True(t, cmp.Equal([]*BlockMeta{meta}, idxP.Meta)) // using cmp.Equal to compare json datetimes + assert.True(t, cmp.Equal([]*CompactedBlockMeta(nil), idxP.CompactedMeta)) // using cmp.Equal to compare json datetimes // json idxJ := &TenantIndex{} err = idxJ.unmarshal(m.writeBuffer[tenantIndexPath]) assert.NoError(t, err) - assert.Equal(t, []*BlockMeta{meta}, idxJ.Metas) - assert.True(t, cmp.Equal([]*BlockMeta{meta}, idxJ.Metas)) // using cmp.Equal to compare json datetimes - assert.True(t, cmp.Equal([]*CompactedBlockMeta(nil), idxJ.CompactedMetas)) // using cmp.Equal to compare json datetimes + assert.Equal(t, []*BlockMeta{meta}, idxJ.Meta) + assert.True(t, cmp.Equal([]*BlockMeta{meta}, idxJ.Meta)) // using cmp.Equal to compare json datetimes + assert.True(t, cmp.Equal([]*CompactedBlockMeta(nil), idxJ.CompactedMeta)) // using cmp.Equal to compare json datetimes // When there are no blocks, the tenant index should be deleted assert.Equal(t, map[string]map[string]int(nil), w.(*writer).w.(*MockRawWriter).deleteCalls) diff --git a/tempodb/backend/tenantindex.go b/tempodb/backend/tenantindex.go index d877a9a7f90..dcebcde1acc 100644 --- a/tempodb/backend/tenantindex.go +++ b/tempodb/backend/tenantindex.go @@ -19,9 +19,9 @@ var _ proto.Message = (*TenantIndex)(nil) func newTenantIndex(meta []*BlockMeta, compactedMeta []*CompactedBlockMeta) *TenantIndex { return &TenantIndex{ - CreatedAt: time.Now(), - Metas: meta, - CompactedMetas: compactedMeta, + CreatedAt: time.Now(), + Meta: meta, + CompactedMeta: compactedMeta, } } diff --git a/tempodb/backend/tenantindex_benchmark_test.go b/tempodb/backend/tenantindex_benchmark_test.go index 4b9c9abee29..1a48d82caa5 100644 --- a/tempodb/backend/tenantindex_benchmark_test.go +++ b/tempodb/backend/tenantindex_benchmark_test.go @@ -10,12 +10,12 @@ import ( func BenchmarkIndexMarshal(b *testing.B) { idx := &TenantIndex{ - Metas: []*BlockMeta{ + Meta: []*BlockMeta{ NewBlockMeta("test", uuid.New(), "v1", EncGZIP, "adsf"), NewBlockMeta("test", uuid.New(), "v2", EncNone, "adsf"), NewBlockMeta("test", uuid.New(), "v3", EncLZ4_4M, "adsf"), }, - CompactedMetas: []*CompactedBlockMeta{ + CompactedMeta: []*CompactedBlockMeta{ { BlockMeta: *NewBlockMeta("test", uuid.New(), "v1", EncGZIP, "adsf"), CompactedTime: time.Now(), @@ -31,8 +31,8 @@ func BenchmarkIndexMarshal(b *testing.B) { }, } - for i := range idx.Metas { - idx.Metas[i].DedicatedColumns = DedicatedColumns{ + for i := range idx.Meta { + idx.Meta[i].DedicatedColumns = DedicatedColumns{ {Scope: "resource", Name: "namespace", Type: "string"}, {Scope: "span", Name: "http.method", Type: "string"}, {Scope: "span", Name: "namespace", Type: "string"}, @@ -47,12 +47,12 @@ func BenchmarkIndexMarshal(b *testing.B) { func BenchmarkIndexUnmarshal(b *testing.B) { idx := &TenantIndex{ - Metas: []*BlockMeta{ + Meta: []*BlockMeta{ NewBlockMeta("test", uuid.New(), "v1", EncGZIP, "adsf"), NewBlockMeta("test", uuid.New(), "v2", EncNone, "adsf"), NewBlockMeta("test", uuid.New(), "v3", EncLZ4_4M, "adsf"), }, - CompactedMetas: []*CompactedBlockMeta{ + CompactedMeta: []*CompactedBlockMeta{ { BlockMeta: *NewBlockMeta("test", uuid.New(), "v1", EncGZIP, "adsf"), CompactedTime: time.Now(), @@ -68,8 +68,8 @@ func BenchmarkIndexUnmarshal(b *testing.B) { }, } - for i := range idx.Metas { - idx.Metas[i].DedicatedColumns = DedicatedColumns{ + for i := range idx.Meta { + idx.Meta[i].DedicatedColumns = DedicatedColumns{ {Scope: "resource", Name: "namespace", Type: "string"}, {Scope: "span", Name: "http.method", Type: "string"}, {Scope: "span", Name: "namespace", Type: "string"}, diff --git a/tempodb/backend/tenantindex_test.go b/tempodb/backend/tenantindex_test.go index 6d68e3fdad0..654c6ab5cbe 100644 --- a/tempodb/backend/tenantindex_test.go +++ b/tempodb/backend/tenantindex_test.go @@ -20,7 +20,7 @@ func TestIndexMarshalUnmarshal(t *testing.T) { { idx: &TenantIndex{ CreatedAt: time.Now(), - Metas: []*BlockMeta{ + Meta: []*BlockMeta{ NewBlockMeta("test", uuid.New(), "v1", EncGZIP, "adsf"), NewBlockMeta("test", uuid.New(), "v2", EncNone, "adsf"), NewBlockMeta("test", uuid.New(), "v3", EncLZ4_4M, "adsf"), @@ -30,7 +30,7 @@ func TestIndexMarshalUnmarshal(t *testing.T) { { idx: &TenantIndex{ CreatedAt: time.Now(), - CompactedMetas: []*CompactedBlockMeta{ + CompactedMeta: []*CompactedBlockMeta{ { BlockMeta: *NewBlockMeta("test", uuid.New(), "v1", EncGZIP, "adsf"), CompactedTime: time.Now(), @@ -48,12 +48,12 @@ func TestIndexMarshalUnmarshal(t *testing.T) { }, { idx: &TenantIndex{ - Metas: []*BlockMeta{ + Meta: []*BlockMeta{ NewBlockMeta("test", uuid.New(), "v1", EncGZIP, "adsf"), NewBlockMeta("test", uuid.New(), "v2", EncNone, "adsf"), NewBlockMeta("test", uuid.New(), "v3", EncLZ4_4M, "adsf"), }, - CompactedMetas: []*CompactedBlockMeta{ + CompactedMeta: []*CompactedBlockMeta{ { BlockMeta: *NewBlockMeta("test", uuid.New(), "v1", EncGZIP, "adsf"), CompactedTime: time.Now(), diff --git a/tempodb/backend/test/backend_test.go b/tempodb/backend/test/backend_test.go index f11d7f07010..f3f7143d549 100644 --- a/tempodb/backend/test/backend_test.go +++ b/tempodb/backend/test/backend_test.go @@ -84,8 +84,8 @@ func TestFixtures(t *testing.T) { var i *backend.TenantIndex i, err = r.TenantIndex(ctx, tenant) require.NoError(t, err) - require.Equal(t, blockMetas, i.Metas) - require.Len(t, i.Metas, len(listMetas)) + require.Equal(t, blockMetas, i.Meta) + require.Len(t, i.Meta, len(listMetas)) } func nonZeroMeta(t *testing.T, m []*backend.BlockMeta) { diff --git a/tempodb/backend/v1.pb.go b/tempodb/backend/v1.pb.go index e06e99ff4f7..9646402569b 100644 --- a/tempodb/backend/v1.pb.go +++ b/tempodb/backend/v1.pb.go @@ -217,9 +217,9 @@ func (m *CompactedBlockMeta) GetCompactedTime() time.Time { } type TenantIndex struct { - CreatedAt time.Time `protobuf:"bytes,1,opt,name=created_at,json=createdAt,proto3,stdtime" json:"createdAt"` - Metas []*BlockMeta `protobuf:"bytes,2,rep,name=metas,proto3" json:"metas,omitempty"` - CompactedMetas []*CompactedBlockMeta `protobuf:"bytes,3,rep,name=compacted_metas,json=compactedMetas,proto3" json:"compacted_metas,omitempty"` + CreatedAt time.Time `protobuf:"bytes,1,opt,name=created_at,json=createdAt,proto3,stdtime" json:"createdAt"` + Meta []*BlockMeta `protobuf:"bytes,2,rep,name=meta,proto3" json:"meta,omitempty"` + CompactedMeta []*CompactedBlockMeta `protobuf:"bytes,3,rep,name=compacted_meta,json=compactedMeta,proto3" json:"compacted_meta,omitempty"` } func (m *TenantIndex) Reset() { *m = TenantIndex{} } @@ -262,16 +262,16 @@ func (m *TenantIndex) GetCreatedAt() time.Time { return time.Time{} } -func (m *TenantIndex) GetMetas() []*BlockMeta { +func (m *TenantIndex) GetMeta() []*BlockMeta { if m != nil { - return m.Metas + return m.Meta } return nil } -func (m *TenantIndex) GetCompactedMetas() []*CompactedBlockMeta { +func (m *TenantIndex) GetCompactedMeta() []*CompactedBlockMeta { if m != nil { - return m.CompactedMetas + return m.CompactedMeta } return nil } @@ -285,56 +285,56 @@ func init() { func init() { proto.RegisterFile("tempodb/backend/v1/v1.proto", fileDescriptor_6bc10ae735c1a340) } var fileDescriptor_6bc10ae735c1a340 = []byte{ - // 784 bytes of a gzipped FileDescriptorProto + // 778 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0xdd, 0x8a, 0xdb, 0x46, - 0x14, 0xb6, 0x76, 0x37, 0x6b, 0x7b, 0x6c, 0xaf, 0xed, 0x09, 0x01, 0xd5, 0x01, 0x8f, 0x31, 0xbd, - 0x70, 0x69, 0x2a, 0xb3, 0x29, 0x29, 0x94, 0xd2, 0x42, 0xb5, 0xdb, 0x96, 0x94, 0xfe, 0x84, 0x49, - 0x72, 0x53, 0x0a, 0x62, 0xa4, 0x19, 0x2b, 0x6a, 0x24, 0x8d, 0x91, 0xc6, 0xa6, 0xcd, 0x53, 0xe4, - 0x69, 0xfa, 0x0c, 0x4b, 0xaf, 0xf6, 0xa6, 0x50, 0x7a, 0x31, 0x2d, 0xde, 0x3b, 0x3d, 0x45, 0x99, - 0x19, 0x59, 0xb2, 0xbd, 0x94, 0xcd, 0xdd, 0x39, 0xe7, 0x3b, 0xdf, 0x99, 0xf9, 0x8e, 0xe6, 0x13, - 0x78, 0x28, 0x58, 0xb2, 0xe4, 0xd4, 0x9f, 0xfb, 0x24, 0x78, 0xcd, 0x52, 0x3a, 0x5f, 0x9f, 0xcf, - 0xd7, 0xe7, 0xce, 0x32, 0xe3, 0x82, 0x43, 0x50, 0x16, 0x9d, 0xf5, 0xf9, 0x08, 0x85, 0x9c, 0x87, - 0x31, 0x9b, 0x6b, 0xc4, 0x5f, 0x2d, 0xe6, 0x22, 0x4a, 0x58, 0x2e, 0x48, 0xb2, 0x34, 0xcd, 0xa3, - 0x8f, 0xc2, 0x48, 0xbc, 0x5a, 0xf9, 0x4e, 0xc0, 0x93, 0x79, 0xc8, 0x43, 0x5e, 0x77, 0xaa, 0x4c, - 0x27, 0x3a, 0x32, 0xed, 0xd3, 0x3f, 0x9a, 0xa0, 0xed, 0xc6, 0x3c, 0x78, 0xfd, 0x3d, 0x13, 0x04, - 0xbe, 0x0f, 0x9a, 0x6b, 0x96, 0xe5, 0x11, 0x4f, 0x6d, 0x6b, 0x62, 0xcd, 0xda, 0x2e, 0x28, 0x24, - 0x3a, 0x5d, 0xf0, 0x2c, 0x21, 0x02, 0x6f, 0x21, 0xf8, 0x39, 0x68, 0xf9, 0x8a, 0xe2, 0x45, 0xd4, - 0x3e, 0x9a, 0x58, 0xb3, 0xae, 0x3b, 0xbd, 0x92, 0xa8, 0xf1, 0xb7, 0x44, 0x27, 0x2f, 0x5f, 0x3e, - 0xbd, 0xdc, 0x48, 0xd4, 0xd4, 0x23, 0x9f, 0x5e, 0x16, 0x12, 0x35, 0x7d, 0x13, 0xe2, 0x32, 0xa0, - 0xf0, 0x09, 0x68, 0x0b, 0x96, 0x92, 0x54, 0x28, 0xfe, 0x3d, 0x7d, 0x8c, 0xbd, 0x91, 0xa8, 0xf5, - 0x42, 0x17, 0x35, 0xa9, 0x25, 0xca, 0x18, 0x6f, 0x23, 0x0a, 0x9f, 0x01, 0x90, 0x0b, 0x92, 0x09, - 0x4f, 0x29, 0xb6, 0x4f, 0x27, 0xd6, 0xac, 0xf3, 0x78, 0xe4, 0x98, 0x75, 0x38, 0x5b, 0x91, 0xce, - 0x8b, 0xed, 0x3a, 0xdc, 0x07, 0xea, 0x4e, 0x85, 0x44, 0x6d, 0xcd, 0x52, 0xf5, 0xb7, 0xff, 0x20, - 0x0b, 0xd7, 0x29, 0xfc, 0x16, 0xb4, 0x58, 0x4a, 0xcd, 0xbc, 0xe6, 0x9d, 0xf3, 0xee, 0x97, 0xf3, - 0x9a, 0x2c, 0xa5, 0xd5, 0xb4, 0x6d, 0x02, 0x9f, 0x80, 0x9e, 0xe0, 0x82, 0xc4, 0x1e, 0xf7, 0x7f, - 0x61, 0x81, 0xc8, 0xed, 0xd6, 0xc4, 0x9a, 0x1d, 0xbb, 0x83, 0x42, 0xa2, 0xae, 0x06, 0x7e, 0x34, - 0x75, 0xbc, 0x97, 0x41, 0x08, 0x4e, 0xf2, 0xe8, 0x0d, 0xb3, 0xdb, 0x13, 0x6b, 0x76, 0x82, 0x75, - 0x0c, 0xbf, 0x00, 0x83, 0x80, 0x27, 0x4b, 0x12, 0x88, 0x88, 0xa7, 0x5e, 0xcc, 0xd6, 0x2c, 0xb6, - 0xc1, 0xc4, 0x9a, 0xf5, 0xdc, 0xfb, 0x85, 0x44, 0xfd, 0x1a, 0xfb, 0x4e, 0x41, 0xf8, 0xb0, 0x00, - 0x1f, 0x29, 0x59, 0x01, 0xa7, 0x51, 0x1a, 0xda, 0x1d, 0xfd, 0x79, 0x06, 0xe5, 0xe7, 0x69, 0x7d, - 0x55, 0xd6, 0x71, 0xd5, 0x01, 0x3f, 0x05, 0xfd, 0x28, 0xa5, 0xec, 0x57, 0x6f, 0x49, 0x42, 0xe6, - 0xe9, 0xcb, 0x74, 0xf5, 0x61, 0xc3, 0x42, 0xa2, 0x9e, 0x86, 0x9e, 0x91, 0x90, 0x3d, 0x8f, 0xde, - 0x30, 0xbc, 0x9f, 0xd6, 0x9a, 0x33, 0x16, 0xf0, 0x8c, 0xe6, 0x76, 0x4f, 0x13, 0x6b, 0xcd, 0xd8, - 0xd4, 0xf1, 0x5e, 0xa6, 0x68, 0x94, 0x08, 0xe2, 0x55, 0x97, 0x3c, 0xd3, 0x6f, 0x40, 0xd3, 0x14, - 0x50, 0x5d, 0x72, 0x2f, 0x83, 0x9f, 0x81, 0xa1, 0x1f, 0x73, 0x9e, 0x78, 0xf9, 0x2b, 0x92, 0x51, - 0x2f, 0xe0, 0xab, 0x54, 0xd8, 0x7d, 0x7d, 0x62, 0xbf, 0x90, 0xa8, 0xa3, 0xc1, 0xe7, 0x0a, 0xcb, - 0x71, 0xbf, 0x4e, 0x2e, 0x54, 0x1f, 0x9c, 0x83, 0xce, 0x82, 0x73, 0xc1, 0x32, 0xa3, 0x70, 0xa0, - 0x69, 0x67, 0x85, 0x44, 0xc0, 0x94, 0xb5, 0xbc, 0x9d, 0x18, 0x06, 0x60, 0x48, 0x19, 0x8d, 0x02, - 0x22, 0x98, 0x3a, 0x2b, 0x5e, 0x25, 0x69, 0x6e, 0x0f, 0xf5, 0x36, 0x3f, 0x29, 0xb7, 0x39, 0xb8, - 0xdc, 0x36, 0x5c, 0x18, 0xbc, 0x90, 0x68, 0x44, 0x0f, 0x6a, 0x8f, 0x78, 0x12, 0x29, 0x6f, 0x8b, - 0xdf, 0xf0, 0xe0, 0x10, 0x83, 0x3f, 0x00, 0x98, 0xb1, 0x65, 0xac, 0x8a, 0xea, 0x53, 0x2f, 0x48, - 0x20, 0x78, 0x66, 0x43, 0x7d, 0x39, 0x54, 0x48, 0xf4, 0x70, 0x07, 0xfd, 0x5a, 0x83, 0x3b, 0xe3, - 0x86, 0xb7, 0xc0, 0xe9, 0xef, 0x16, 0x80, 0x17, 0xe6, 0x35, 0x30, 0x5a, 0xbb, 0xda, 0x05, 0xc0, - 0xf8, 0x35, 0x61, 0x82, 0x68, 0x63, 0x77, 0x1e, 0x3f, 0x70, 0xea, 0x9f, 0x8a, 0x53, 0xb5, 0xba, - 0x5d, 0xa5, 0xed, 0x5a, 0x22, 0xab, 0x90, 0xa8, 0x81, 0xdb, 0x7e, 0x35, 0xe3, 0x67, 0x70, 0x16, - 0x6c, 0x27, 0x1b, 0xc7, 0x1c, 0xdd, 0xe9, 0x98, 0xf7, 0x4a, 0xc7, 0xf4, 0x2a, 0x66, 0xe5, 0x9b, - 0xfd, 0xd2, 0xf4, 0x4f, 0x0b, 0x74, 0x4a, 0xfb, 0xab, 0x17, 0xa6, 0xbc, 0x1e, 0x64, 0x4c, 0xef, - 0x9e, 0x88, 0xf2, 0xc6, 0xef, 0xe4, 0xf5, 0x92, 0xf5, 0xa5, 0x30, 0x5e, 0xaf, 0x52, 0xf8, 0x21, - 0xb8, 0xa7, 0xd4, 0xe7, 0xf6, 0xd1, 0xe4, 0xf8, 0x7f, 0xe5, 0x63, 0xd3, 0x03, 0xbf, 0x01, 0xfd, - 0x5a, 0xac, 0xa1, 0x1d, 0x6b, 0xda, 0x78, 0x97, 0x76, 0x7b, 0xd3, 0xb8, 0xde, 0x91, 0x4a, 0x73, - 0xf7, 0x83, 0xab, 0xcd, 0xd8, 0xba, 0xde, 0x8c, 0xad, 0x7f, 0x37, 0x63, 0xeb, 0xed, 0xcd, 0xb8, - 0x71, 0x7d, 0x33, 0x6e, 0xfc, 0x75, 0x33, 0x6e, 0xfc, 0xd4, 0x3f, 0xf8, 0xe1, 0xfb, 0xa7, 0x5a, - 0xd6, 0xc7, 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0x8e, 0xd1, 0x6d, 0x86, 0x0a, 0x06, 0x00, 0x00, + 0x14, 0xb6, 0x76, 0xdd, 0xb5, 0x3d, 0xb6, 0xd7, 0xf6, 0x84, 0x80, 0xea, 0x80, 0xc7, 0x98, 0x5e, + 0x38, 0x90, 0xca, 0x6c, 0x4a, 0x0a, 0xa5, 0xb4, 0x50, 0xed, 0xa6, 0x90, 0xd2, 0x9f, 0xa0, 0x24, + 0x37, 0xa5, 0x20, 0x46, 0x9a, 0xb1, 0xa2, 0x46, 0xd2, 0x18, 0x69, 0x6c, 0xda, 0x3c, 0x45, 0x9e, + 0xa6, 0xcf, 0x10, 0x7a, 0xb5, 0xbd, 0x2b, 0xbd, 0x98, 0x16, 0xef, 0x9d, 0x9e, 0xa2, 0xcc, 0x91, + 0x2c, 0xd9, 0x5e, 0xca, 0xf6, 0xee, 0x9c, 0xf3, 0x9d, 0xef, 0xcc, 0x7c, 0x47, 0xf3, 0x09, 0x3d, + 0x90, 0x3c, 0x5e, 0x09, 0xe6, 0x2d, 0x3c, 0xea, 0xbf, 0xe1, 0x09, 0x5b, 0x6c, 0x2e, 0x16, 0x9b, + 0x0b, 0x6b, 0x95, 0x0a, 0x29, 0x30, 0x2a, 0x8b, 0xd6, 0xe6, 0x62, 0x4c, 0x02, 0x21, 0x82, 0x88, + 0x2f, 0x00, 0xf1, 0xd6, 0xcb, 0x85, 0x0c, 0x63, 0x9e, 0x49, 0x1a, 0xaf, 0x8a, 0xe6, 0xf1, 0xc7, + 0x41, 0x28, 0x5f, 0xaf, 0x3d, 0xcb, 0x17, 0xf1, 0x22, 0x10, 0x81, 0xa8, 0x3b, 0x75, 0x06, 0x09, + 0x44, 0x45, 0xfb, 0xec, 0xf7, 0x16, 0xea, 0xd8, 0x91, 0xf0, 0xdf, 0x7c, 0xc7, 0x25, 0xc5, 0x1f, + 0xa1, 0xd6, 0x86, 0xa7, 0x59, 0x28, 0x12, 0xd3, 0x98, 0x1a, 0xf3, 0x8e, 0x8d, 0x72, 0x45, 0xce, + 0x96, 0x22, 0x8d, 0xa9, 0x74, 0x76, 0x10, 0xfe, 0x02, 0xb5, 0x3d, 0x4d, 0x71, 0x43, 0x66, 0x9e, + 0x4c, 0x8d, 0x79, 0xcf, 0x9e, 0xbd, 0x57, 0xa4, 0xf1, 0x97, 0x22, 0xcd, 0x57, 0xaf, 0x9e, 0x5d, + 0x6d, 0x15, 0x69, 0xc1, 0xc8, 0x67, 0x57, 0xb9, 0x22, 0x2d, 0xaf, 0x08, 0x9d, 0x32, 0x60, 0xf8, + 0x09, 0xea, 0x48, 0x9e, 0xd0, 0x44, 0x6a, 0xfe, 0x07, 0x70, 0x8c, 0xb9, 0x55, 0xa4, 0xfd, 0x12, + 0x8a, 0x40, 0x6a, 0xcb, 0x32, 0x76, 0x76, 0x11, 0xc3, 0xcf, 0x11, 0xca, 0x24, 0x4d, 0xa5, 0xab, + 0x15, 0x9b, 0x67, 0x53, 0x63, 0xde, 0x7d, 0x3c, 0xb6, 0x8a, 0x75, 0x58, 0x3b, 0x91, 0xd6, 0xcb, + 0xdd, 0x3a, 0xec, 0xfb, 0xfa, 0x4e, 0xb9, 0x22, 0x1d, 0x60, 0xe9, 0xfa, 0xbb, 0xbf, 0x89, 0xe1, + 0xd4, 0x29, 0xfe, 0x06, 0xb5, 0x79, 0xc2, 0x8a, 0x79, 0xad, 0x3b, 0xe7, 0xdd, 0x2b, 0xe7, 0xb5, + 0x78, 0xc2, 0xaa, 0x69, 0xbb, 0x04, 0x3f, 0x41, 0x7d, 0x29, 0x24, 0x8d, 0x5c, 0xe1, 0xfd, 0xcc, + 0x7d, 0x99, 0x99, 0xed, 0xa9, 0x31, 0x3f, 0xb5, 0x87, 0xb9, 0x22, 0x3d, 0x00, 0x7e, 0x28, 0xea, + 0xce, 0x41, 0x86, 0x31, 0x6a, 0x66, 0xe1, 0x5b, 0x6e, 0x76, 0xa6, 0xc6, 0xbc, 0xe9, 0x40, 0x8c, + 0xbf, 0x44, 0x43, 0x5f, 0xc4, 0x2b, 0xea, 0xcb, 0x50, 0x24, 0x6e, 0xc4, 0x37, 0x3c, 0x32, 0xd1, + 0xd4, 0x98, 0xf7, 0xed, 0x7b, 0xb9, 0x22, 0x83, 0x1a, 0xfb, 0x56, 0x43, 0xce, 0x71, 0x01, 0x3f, + 0xd2, 0xb2, 0x7c, 0xc1, 0xc2, 0x24, 0x30, 0xbb, 0xf0, 0x79, 0x86, 0xe5, 0xe7, 0x69, 0x3f, 0x2d, + 0xeb, 0x4e, 0xd5, 0x81, 0x3f, 0x43, 0x83, 0x30, 0x61, 0xfc, 0x17, 0x77, 0x45, 0x03, 0xee, 0xc2, + 0x65, 0x7a, 0x70, 0xd8, 0x28, 0x57, 0xa4, 0x0f, 0xd0, 0x73, 0x1a, 0xf0, 0x17, 0xe1, 0x5b, 0xee, + 0x1c, 0xa6, 0xb5, 0xe6, 0x94, 0xfb, 0x22, 0x65, 0x99, 0xd9, 0x07, 0x62, 0xad, 0xd9, 0x29, 0xea, + 0xce, 0x41, 0xa6, 0x69, 0x8c, 0x4a, 0xea, 0x56, 0x97, 0x3c, 0x87, 0x37, 0x00, 0x34, 0x0d, 0x54, + 0x97, 0x3c, 0xc8, 0xf0, 0xe7, 0x68, 0xe4, 0x45, 0x42, 0xc4, 0x6e, 0xf6, 0x9a, 0xa6, 0xcc, 0xf5, + 0xc5, 0x3a, 0x91, 0xe6, 0x00, 0x4e, 0x1c, 0xe4, 0x8a, 0x74, 0x01, 0x7c, 0xa1, 0xb1, 0xcc, 0x19, + 0xd4, 0xc9, 0xa5, 0xee, 0xc3, 0x0b, 0xd4, 0x5d, 0x0a, 0x21, 0x79, 0x5a, 0x28, 0x1c, 0x02, 0xed, + 0x3c, 0x57, 0x04, 0x15, 0x65, 0x90, 0xb7, 0x17, 0x63, 0x1f, 0x8d, 0x18, 0x67, 0xa1, 0x4f, 0x25, + 0xd7, 0x67, 0x45, 0xeb, 0x38, 0xc9, 0xcc, 0x11, 0x6c, 0xf3, 0xd3, 0x72, 0x9b, 0xc3, 0xab, 0x5d, + 0xc3, 0x65, 0x81, 0xe7, 0x8a, 0x8c, 0xd9, 0x51, 0xed, 0x91, 0x88, 0x43, 0xed, 0x6d, 0xf9, 0xab, + 0x33, 0x3c, 0xc6, 0xf0, 0xf7, 0x08, 0xa7, 0x7c, 0x15, 0xe9, 0xa2, 0xfe, 0xd4, 0x4b, 0xea, 0x4b, + 0x91, 0x9a, 0x18, 0x2e, 0x47, 0x72, 0x45, 0x1e, 0xec, 0xa1, 0x5f, 0x03, 0xb8, 0x37, 0x6e, 0x74, + 0x0b, 0x9c, 0xfd, 0x66, 0x20, 0x7c, 0x59, 0xbc, 0x06, 0xce, 0x6a, 0x57, 0xdb, 0x08, 0x15, 0x7e, + 0x8d, 0xb9, 0xa4, 0x60, 0xec, 0xee, 0xe3, 0xfb, 0x56, 0xfd, 0x53, 0xb1, 0xaa, 0x56, 0xbb, 0xa7, + 0xb5, 0x5d, 0x2b, 0x62, 0xe4, 0x8a, 0x34, 0x9c, 0x8e, 0x57, 0xcd, 0xf8, 0x09, 0x9d, 0xfb, 0xbb, + 0xc9, 0x85, 0x63, 0x4e, 0xee, 0x74, 0xcc, 0x87, 0xa5, 0x63, 0xfa, 0x15, 0xb3, 0xf2, 0xcd, 0x61, + 0x69, 0xf6, 0x87, 0x81, 0xba, 0xa5, 0xfd, 0xf5, 0x0b, 0xd3, 0x5e, 0xf7, 0x53, 0x0e, 0xbb, 0xa7, + 0xb2, 0xbc, 0xf1, 0xff, 0xf2, 0x7a, 0xc9, 0xfa, 0x4a, 0x16, 0x5e, 0xaf, 0x52, 0xfc, 0x10, 0x35, + 0x41, 0xfd, 0xc9, 0xf4, 0xf4, 0x3f, 0xd5, 0x3b, 0xd0, 0x82, 0x9f, 0xee, 0x4b, 0x05, 0xd2, 0x29, + 0x90, 0x26, 0xfb, 0xa4, 0xdb, 0x6b, 0xde, 0xd3, 0x04, 0xab, 0x7c, 0xf8, 0x7e, 0x3b, 0x31, 0xae, + 0xb7, 0x13, 0xe3, 0x9f, 0xed, 0xc4, 0x78, 0x77, 0x33, 0x69, 0x5c, 0xdf, 0x4c, 0x1a, 0x7f, 0xde, + 0x4c, 0x1a, 0x3f, 0x0e, 0x8e, 0x7e, 0xf6, 0xde, 0x19, 0x48, 0xfa, 0xe4, 0xdf, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xfe, 0x92, 0x00, 0xfe, 0x06, 0x06, 0x00, 0x00, } func (m *BlockMeta) Marshal() (dAtA []byte, err error) { @@ -534,10 +534,10 @@ func (m *TenantIndex) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.CompactedMetas) > 0 { - for iNdEx := len(m.CompactedMetas) - 1; iNdEx >= 0; iNdEx-- { + if len(m.CompactedMeta) > 0 { + for iNdEx := len(m.CompactedMeta) - 1; iNdEx >= 0; iNdEx-- { { - size, err := m.CompactedMetas[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + size, err := m.CompactedMeta[iNdEx].MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -548,10 +548,10 @@ func (m *TenantIndex) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x1a } } - if len(m.Metas) > 0 { - for iNdEx := len(m.Metas) - 1; iNdEx >= 0; iNdEx-- { + if len(m.Meta) > 0 { + for iNdEx := len(m.Meta) - 1; iNdEx >= 0; iNdEx-- { { - size, err := m.Metas[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + size, err := m.Meta[iNdEx].MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -660,14 +660,14 @@ func (m *TenantIndex) Size() (n int) { _ = l l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt) n += 1 + l + sovV1(uint64(l)) - if len(m.Metas) > 0 { - for _, e := range m.Metas { + if len(m.Meta) > 0 { + for _, e := range m.Meta { l = e.Size() n += 1 + l + sovV1(uint64(l)) } } - if len(m.CompactedMetas) > 0 { - for _, e := range m.CompactedMetas { + if len(m.CompactedMeta) > 0 { + for _, e := range m.CompactedMeta { l = e.Size() n += 1 + l + sovV1(uint64(l)) } @@ -1324,7 +1324,7 @@ func (m *TenantIndex) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Metas", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Meta", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1351,14 +1351,14 @@ func (m *TenantIndex) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Metas = append(m.Metas, &BlockMeta{}) - if err := m.Metas[len(m.Metas)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.Meta = append(m.Meta, &BlockMeta{}) + if err := m.Meta[len(m.Meta)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CompactedMetas", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field CompactedMeta", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1385,8 +1385,8 @@ func (m *TenantIndex) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.CompactedMetas = append(m.CompactedMetas, &CompactedBlockMeta{}) - if err := m.CompactedMetas[len(m.CompactedMetas)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.CompactedMeta = append(m.CompactedMeta, &CompactedBlockMeta{}) + if err := m.CompactedMeta[len(m.CompactedMeta)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/tempodb/backend/v1/v1.proto b/tempodb/backend/v1/v1.proto index 7a9e319663f..b6617f1c8f6 100644 --- a/tempodb/backend/v1/v1.proto +++ b/tempodb/backend/v1/v1.proto @@ -34,6 +34,6 @@ message CompactedBlockMeta { message TenantIndex { google.protobuf.Timestamp created_at = 1[(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = "createdAt"]; - repeated BlockMeta metas = 2; - repeated CompactedBlockMeta compacted_metas = 3; + repeated BlockMeta meta = 2; + repeated CompactedBlockMeta compacted_meta = 3; } diff --git a/tempodb/blocklist/poller.go b/tempodb/blocklist/poller.go index d14d9c0e9a8..e2fc1ed2751 100644 --- a/tempodb/blocklist/poller.go +++ b/tempodb/blocklist/poller.go @@ -256,11 +256,11 @@ func (p *Poller) pollTenantAndCreateIndex( if err == nil { // success! return the retrieved index metricTenantIndexAgeSeconds.WithLabelValues(tenantID).Set(float64(time.Since(i.CreatedAt) / time.Second)) - level.Info(p.logger).Log("msg", "successfully pulled tenant index", "tenant", tenantID, "createdAt", i.CreatedAt, "metas", len(i.Metas), "compactedMetas", len(i.CompactedMetas)) + level.Info(p.logger).Log("msg", "successfully pulled tenant index", "tenant", tenantID, "createdAt", i.CreatedAt, "metas", len(i.Meta), "compactedMetas", len(i.CompactedMeta)) - span.SetAttributes(attribute.Int("metas", len(i.Metas))) - span.SetAttributes(attribute.Int("compactedMetas", len(i.CompactedMetas))) - return i.Metas, i.CompactedMetas, nil + span.SetAttributes(attribute.Int("metas", len(i.Meta))) + span.SetAttributes(attribute.Int("compactedMetas", len(i.CompactedMeta))) + return i.Meta, i.CompactedMeta, nil } metricTenantIndexErrors.WithLabelValues(tenantID).Inc() From cc30cbd8224dc9dba70885df67d9f3041acabbb8 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Tue, 1 Oct 2024 15:11:51 +0000 Subject: [PATCH 70/71] Import original tenantindex and test contents for backwards compatibility --- tempodb/backend/test/backend_test.go | 72 +++++++++++- .../backend/test/test-data/3/index.json.gz | Bin 0 -> 1563985 bytes tempodb/backend/v1.pb.go | 105 +++++++++--------- tempodb/backend/v1/v1.proto | 4 +- 4 files changed, 123 insertions(+), 58 deletions(-) create mode 100644 tempodb/backend/test/test-data/3/index.json.gz diff --git a/tempodb/backend/test/backend_test.go b/tempodb/backend/test/backend_test.go index f3f7143d549..fdf4a5d9841 100644 --- a/tempodb/backend/test/backend_test.go +++ b/tempodb/backend/test/backend_test.go @@ -49,10 +49,6 @@ func TestFixtures(t *testing.T) { require.NoError(t, err) require.Len(t, listCompactedMetas, 1) - for _, v := range listMetas { - t.Logf("listMetas: %v", v) - } - blockMetas := make([]*backend.BlockMeta, 0, len(listMetas)) for _, u := range listMetas { m, e := r.BlockMeta(ctx, u, tenant) @@ -88,6 +84,74 @@ func TestFixtures(t *testing.T) { require.Len(t, i.Meta, len(listMetas)) } +func TestOriginalFixtures(t *testing.T) { + var ( + tenant = "3" // A sample index + ctx = context.Background() + ) + + rr, rw, _, err := local.New(&local.Config{ + Path: "./test-data", + }) + require.NoError(t, err) + + var ( + _ = backend.NewWriter(rw) + r = backend.NewReader(rr) + ) + + expectedDedicatedColumns := backend.DedicatedColumns{ + backend.DedicatedColumn{Scope: "span", Name: "db.statement", Type: "string"}, + backend.DedicatedColumn{Scope: "span", Name: "component", Type: "string"}, + backend.DedicatedColumn{Scope: "span", Name: "http.user_agent", Type: "string"}, + backend.DedicatedColumn{Scope: "span", Name: "otel.library.name", Type: "string"}, + backend.DedicatedColumn{Scope: "span", Name: "db.connection_string", Type: "string"}, + backend.DedicatedColumn{Scope: "span", Name: "organization", Type: "string"}, + backend.DedicatedColumn{Scope: "span", Name: "peer.address", Type: "string"}, + backend.DedicatedColumn{Scope: "span", Name: "net.peer.name", Type: "string"}, + backend.DedicatedColumn{Scope: "span", Name: "blockID", Type: "string"}, + backend.DedicatedColumn{Scope: "span", Name: "db.name", Type: "string"}, + backend.DedicatedColumn{Scope: "resource", Name: "host.name", Type: "string"}, + backend.DedicatedColumn{Scope: "resource", Name: "opencensus.exporterversion", Type: "string"}, + backend.DedicatedColumn{Scope: "resource", Name: "client-uuid", Type: "string"}, + backend.DedicatedColumn{Scope: "resource", Name: "ip", Type: "string"}, + backend.DedicatedColumn{Scope: "resource", Name: "database", Type: "string"}, + backend.DedicatedColumn{Scope: "resource", Name: "os.description", Type: "string"}, + backend.DedicatedColumn{Scope: "resource", Name: "process.runtime.description", Type: "string"}, + backend.DedicatedColumn{Scope: "resource", Name: "container.id", Type: "string"}, + backend.DedicatedColumn{Scope: "resource", Name: "slug", Type: "string"}, + backend.DedicatedColumn{Scope: "resource", Name: "module.path", Type: "string"}, + } + + i, err := r.TenantIndex(ctx, tenant) + assert.NoError(t, err) + assert.NotNil(t, i) + + assert.Equal(t, 22435, len(i.Meta)) + assert.Equal(t, 3264, len(i.CompactedMeta)) + + nonZeroMeta(t, i.Meta) + for _, v := range i.Meta { + assert.Equal(t, tenant, v.TenantID) + assert.Equal(t, "vParquet4", v.Version) + assert.NotZero(t, v.StartTime) + assert.NotZero(t, v.EndTime) + assert.Equal(t, 20, len(v.DedicatedColumns)) + assert.Equal(t, expectedDedicatedColumns, v.DedicatedColumns) + } + + nonZeroCompactedMeta(t, i.CompactedMeta) + for _, v := range i.CompactedMeta { + assert.Equal(t, "vParquet4", v.Version) + assert.Equal(t, tenant, v.TenantID) + assert.NotZero(t, v.CompactedTime) + assert.NotZero(t, v.StartTime) + assert.NotZero(t, v.EndTime) + assert.Equal(t, 20, len(v.DedicatedColumns)) + assert.Equal(t, expectedDedicatedColumns, v.DedicatedColumns) + } +} + func nonZeroMeta(t *testing.T, m []*backend.BlockMeta) { for _, v := range m { assert.NotZero(t, v.BlockID, "blockid is zero, id: %v", v.BlockID) diff --git a/tempodb/backend/test/test-data/3/index.json.gz b/tempodb/backend/test/test-data/3/index.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..2399ab6e0c1892ad6a7262ab992668be59ae5c52 GIT binary patch literal 1563985 zcmV)iK%&1NiwFn+32ul0|7mVyWq2-Xb8l_{?44b2TuE;Cze``623aJF9=W1{^8G;KgqxE+D$Ka zeg1Q~+fBQKNq`WL{)9Xwo`l{9Yi2~}f7!j;ed>2*H~s71cgyw7r~9}3{4TNU7}J?e6+jxw^Z52k+kPZtu#? z-Jd>u>JMK9hpXRq)9&i}s_)+IK3vWHuYV}N z^*`Q!0)G1+{Bv*DH}maoBEomOx!jfivw!Q?pTza2KmK06z2@C+xxT*ZH(x)5LfG>9 zzCM3w>relGU4Q)Y>FW0WCwsM{Qk>r zzxi|d?fb{C@A}90A3xNaa`RvBuga(X_!)D3->$E&`u(5#&$o9s>mT;v$?Kcn%GHOz zmG!yD2S4|I^S;dUO~1W;eDJE@y}y6rhYx@F^*{XgT=&o4?xx*MzrFr))B5h+{nNi+ z-`>6Wg6q%ys`abeFSqaeUq4^p-1VEk^qbpJGkq`7r50hzxi@?_u*52&0E^_)m`~;)o;mkyTcW)5o;K2{{34w+ z5k99=R5Hs0oyx>WZpi0?Q{^a|`A0NEoizL2NPbNCLT8;9OPB zViTD<(aU7|gmg$ZH8SsYGb84Ns&O{mL_a|{5mjR7=FrW{=q6+GR)nC;l|U8`h{YLF zp}t5di!9rsTAk?SsP-Z3{V}SQEXnq|DQ@B<`D}1%-mIIEQsP18AoDV0V$7IqSzzgN z1({O@pSeS=y||GyT;`2rCVG*~d@$b>rRP@*qnH9B@bFPV6_M(Zr>4`dSNWSlG~I~SUSag@#HHQHooqY^YKK^Lk7 zEh$x>!@*LiAe9`vxq{UeHKHWSTPs0F=*&|(M5nQ3<-Undn=oFalYUYX(%74WR1if~ zg3bl!DaBfL8)ObLFGQxMBuh#iEJ*_)WvHzow91-8I4#Szr1L15I*~lrP05;KPbLde zxbWF>&Qr+ra2jL|GA~0W=d{$N8ML-I$TD{*8UfzKB3Q^mHk zYmriBjyPo5lT$R)j+bivNjS@aDUC|)sMNkirS{$Krhopp{=NEeef57!ySu*GP4o(2 zg(Al+6_S~Qq}jp61jNmho7U8ABd|vt@G{<72-%kN{5ub zg_NGms};>Aj6m2I5GylOWP_?*au^f≀3R@^VGjrgX>?FNt#6^Qz{8u5vbBPY8Xp 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∓M{2fApP3RwN~q&Vuuq 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 z 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�KspZtw)UKxXNloq6HgD86 z*sUncY;K6wHkb*Ty69}tG(n3?(mp)Pv8L9p>VbG3ZI+AgO)UJ0rdtrE^K%`&!gy89RW+Yf zHG{P8g&fQ?K}r@#osZ5ezK_v(_gu^lDysG(#=pY@}TXVfN zpY+xwEyPYc?1>d*8v@}Gz`H2(u9e9SqRCfQoBXPxy|mgCrSc&<(BPyZ_GH^2%~+1_ z%klj;9N+Iy9fYJ>cY~ZEWn#@BbW`w9?7~5HJ9JO2_99o(Q+Rs2mrJ`%j=us0)s<7& z&$D)aq-t^&T^F0{V)IECo6;=QIzbk1Ac_I$b%zptjJ;9c_G4opf59skoBSer+3J9% z@8#!PQ`OwgG~0UwO{I0Pxehj;b+EZ*$5vy&Ovwh>BcPc&Ac}ZZVLOiI6@wuDXR0Tq z$H(o7xp|6V*ab8ni{ZVE<`1(yK8)-RhT{_jOGheiXooY=037gS$CZ4j`MkUoWfF+lt8m8NOy{6eB>8d36>C}^J=LaMw2*$S1nz&^#7`sviHW$2v|fw zWV5%V1|w;)5hETH_W4y4_%~oL7}r{ge0n1IbQlZF^MLi+s=oYIOJ}H&uXpKsm;T1P z^x@{0EZeqsfi6Wr_TC};zC*T6(eX7T`*dJ0HNP2u+1Z+)Nni>64=e2V*D96bwyfco zHT?gTH9UKo(5BE^pC-2@APaTy9xP;u)Q?@Y_>Fz(94}pv&RfCPIqy5L$;BxzyAD0p z65oEU{unP&h^(uYb=C44S1k`$*sW)E6osw4o}tOBP1t~;owqHwk@b+d<^=Zo7Bw%P zp&6#ihrq#nCg8H4*Am<9miR}7jS{rpu>Y}vwi%i?2kcYF zi*1L9+5oHcszF1`pOTW$;aq8AR+tmI$jVUDC~X?R-m>v(e>{G<6T#TS|j&0j(D z@$phsqDs)5A3iBYZ~$&;7%y>ooo_9_`QP$dsooa30C_H81OaX5G*H%Kgm4zzVVVumNgy2dO$Bq7g9H$TC>ResmtJ*T+k8 z5!e~w@^`kc6=gZ`Ox$k2VSkL5)Y5YSyMX-#VDD&tJDHAD0^E73moOoT614gV+9+$` zLukee-CEULQUZ$^+Q;NqQoKlp`dPJ9Z=-2n(G2$xT4XLVe}T-0OX-eYv*mzhxq-CS zq4H+17cLtzkG&k5F2yY~qVLPu`9UOD8&Wr0`_!Z?CNAq6G=)FVG*XP|A$VGsYquvxKdNS$FOB}v z=>LCd^m&g`xNp$+snH+Zp_*@?o?B)VLpydro<?U>m^zLR&QmR@{;YPfs`jn3O~MNNNd zo6Cik8h@$re?yIbN7dYAs8`vbFcuJYf!w=8vH(Vkf~OX9M1Shfz&vUR9|du&C(%Zz_vQHZTJ;E}QgH`0Efq2(9E_o8^EYT~68 zC`;1Eo<%)bxnL_zKd+7AE=uAg7i+_ zKhg9Ty7bm86!;gKNKvxLd1yYgQsG!T(6s~ojUDJ64K0?=*pOi7EFk6ywU!PPOyZ$i z;{(#%S2S-Pl3pAGF}^wvy?cIIauTyY7tO+JrLtBk&swQ?>lC9H)C~z_A3H>E2HR#< zWb8YS11ps`G_N>jy3V!k5NC8f5l?W=yXZJ2M6N0W_s>S<92PJbBXcq!h26 z)4+40iIPyg%hcQ|6H6H=2ho)4*WB@fm)t$Mh<~E#5-I*{6MG?Cw`S|s>^E-B?s#kV zT_tm4*meq#t_JDNpp;Uhi?HJXqXm9Je$PYuCz^Wk3{*=g`qvmJBO^*YSH4Fk3(bY* zlhCB@gHjx})&-vk3E*JXV&>DTp_cW#o3CnYpwZ$CQ z7-)@wo-_t(xc8R(d|}cCf_3II5rOT|&82#)$KIOrc=IZndik`oQ1Q>xPA9aYV&@6< z9+}We_(%Hi=fZ8P9+R zyoLCMZi<2QJ?rornq|gAe4?oZ-JJL|G#}|_<24a#-B+*s>Sx?n*Sa}#8Bl!gHhT`J zr4ejZTw>r}^*{{7E1EY#3*%k>{tZou*OAMgwI&9uQJyCTdZcO=UD@0#oBLVW+&*^M z%?w7929j2xP2=0xW!4NDPDjza;UAwbbjkXFS^p9PSvm6x$kU5r~-($ z;FAcU&HOjFaLh0hVRMIS(OZ{a@pok*bJ7lM{aks_}9ojfLJzd#ad_AI{UJ9HfUxy>kza#i1Z58YC?2vnJW@czCCD2j=y+{ev(YI}nqvggOWTrs#x$m@H(7e~Cr;TzpSI;toB97j3RIcqLGVc}r@sE}hOtX*f>pjFhNwr+31A0sWeV>_Ox_bUr z&)>^>{#3B|oDkI!qz6KboPT$gi{5G#44Hqd7*C;qt7FTO#uxL7V|E@=J+G@ov+<~B<9w!zRDyQa3l9(4fe zTZ}?moq5WLqJCFX%QyXB0N*#jip8h1+ST?1FEYKVgVW_SU>Qr~QtmC~-ft-Po(62g zmT1zT=U$o{qeHefL90xvvt_i40efsu(PI9oO)wGHRJ+bOW{&~;jm#w~S$F|<0rocl z`!`bCUZyv9*jueZHcx1~Nrm0VY^9RWsjS+Ev-F1#s1+&kp-phchzwM^s?YkF<=2dn z7c>_%e*v0L&(eXV7mNyt5qD4Bl>u<+;Kr~;n`Y?p4% z8Bk)YARz$_#{^U%M-JZRIeIDnLSKKBv7lP=)0Cz}PCMgt6=3!8O8hqNT&3h z79!Tebv;~vNI$ z=9|b357t~sbNb+s)Q!bd{5lKU<2Co&SxShe%lEx}->>q0XBuOmL(e@gw?#rra^UWo zGbyl~2pD^Vrrf7^EN5 zJYnr5?n^hmKVaj= zN0IbzA@m=3jXi0_&E&G(_nC$zBws$6<&$}lPeydpF?oZ)UO=iCH1x3tU+XYx?s+1= z;cb-OSMh4z_&^k>$@bY6;ixRUyH2kfrS@3G`~A;S$P|}mVQChAL$mPo?n^y53?rnD8m)@}(Z%lSIh%|57@CpeZt6`rM_@{SAHYUkDetx#q?NqVBGizzG#S z!O~*e8f{}cN8a*{?=nQ3H#``eqHg7jaDgKfDXxR&W83IAXlD4z-d)+dFU#KTWWC8| z;MNL=CPR`rTT}1yKnuhriKc=x8Si}r38=6mj zJi`_dw1}V=5kbb*HjfFDEkJk+Xmt#T*^-E=c04B@()WkvkI;;F4)@>C3?Y&aXc8tG z7h=n+7Fxo`;QWIKN@S-cAX);V-w+V}#o+Yp(l)K2Z8}Jq}AP*ktLf;bQ#vcddeQ+S0NJ#%H*y+OU!;w zU~4zEy9+J<;QK86g{0jx=snf1V}hQ6W*{w+c9FC%B58Xx+oC%#GJ}{gq?ZcJ>5igZ z_}tX=8{WS)`PfG0tY3mmOw2UMUMSWh+&`;}23j=Gi)bJz8!AqQ=G;MY7_@>F)HMt@ zM${AaEqp_N5dS54d~0T?eL~aK!np8jp=rLW?3e0bsSaMEI+(;$d4d#okhZ5KBz34N zv}ETpLMqCEXr=}*y${1Q1Lodo0it0v% z9Yj?@VpOPGOyCi%w2r>aHL z)PEs47>r%VG{C{TXVVQDmkqY0=2=4c++UOMo#puvntAM~W@r3#RHGr2{6pGaB?!`o z;QYf;9pZ21v~_N-bMqDFCQjd?4uh0hL3jv6&jCE=rbKNtIfu@2!@E1}F4sFkr>WY9 z>VWpZ10#uY*#m_L&!aO%U6z=3iD_RXrrkj~ss!k^2Tsqddtt9avB=H5$2Lw`P^jF> z{a%$gj1Tg3lP|Ngct$bO%l2Br$60)T%uWxH74Egdy^u5&RM|9d@u&uc3XXB^t9_x%0y$YPq@j>eAi?Y5bulk~p)E$GcNePf` zFHvDDpkypGJtreJp_v54?hWxVznn%{HxC>YC<1ua?7Z^(k4 z&fV*^m1)`mw~io;6{^LA>d{9k)lpCVR#bkTrTqW)P9#5$K@g5F#uVM}($otRN}h>9 zSoIC7zTtKC4WrgF3&BM1AUZ1q%Y>o5(ZndFp2`kV`8lBE4Vm&ovx>0T#|^3)f`Ka6 zrAt49%&?{6TPnU6srZPuOqUICYZHVkLM^Sq79|H|Nw;wpnLpW5-jJzr(}UdiLN2Z! zL$d@6MKO<~uv&g*%`Ne`!@lIdZ&1Y`l(p!tMfW!r-M<)|YT7GAc}#^W3G8#GA;nU-s8xyD}P8cUqj zls9Nh17v50l7qoF>S3L|ovS2My_NgWJWi_(+r23NgC^|-Wkpl3t4tw!+*tp|UnO^U z&f06&Ui+fGw(O*>D1(Ot2+@E{A28iVaBYO!sRnG-pA|#@ppy<2LlR71Qr?5rGo@T- zw|?Bf@W)?83dP!K*G~JQoz@4LjM-uK*iTM(2o$ZTsw%mq|i2>!UW|zmdw*U&%CQ)aj-rBiy z)82>Tk2`JN_^_NlG(R)mQzO_6FHnpw+*sn0?ppWaM_xkNA_EmVOHS`UkLh!^2rh`lXd& zPkwjI>rB|sU7(taw_UvLt9V4r7TR@+LN_FkEjrX01+=+tuB_8f)u=oK zEc=ZPw0&Y>@geO~m%Rr~udAVdD$t}zS*Gk|%6^q8n^UU{gf=F^ej7q#Q^2&^rcIu9 zPM+X5x-YxU_mY)wvy?LZBMsiHI4K=Bc0P5N+G9cdAG6dPdFlF=uJ1Q=eNWF)cXFKJ zz}5DQ6B!VrAZT%IJ0+vjEZ{T~BqAWJ2TU@;tyGI~suOz$tUh?k9JQ1wrpZUJf@$I|z;pRO zoUq@QUvg$&MA9OXeuGGQ8nD6zwPb+Ky&wrEL1+z_letuN7Ccq;p#F1C(Fb4;LaWtN z=wl`J5__kgcwDs-`(riz_m#MqnXOvE|6Z-&|7Y)7a+Fzm<%%rX={LK{N9F#Pa8-T! z>+aL=0fpe_NH--WHDVMBXE+@3{~EB}YSyhf&__#e=mwD^fIH2o7O~+`J-FO73tk8o zQ$hLhhIP|q*J4k5!``+%oV{T~443U;*&beDdw7^(jgpwuAVxAs)B!nKz>t*L8q1bP z8J2G`tX^8+Xt;e@2rW_(S?GBq@ohc$jA60hvJfr{;Y%!p4+EBRs&pUF$OFVhpjywp z79Xb(Z$9Tyz+QDPNuKbM=huYdI~*_s&D2VHnz8T!&o4*V0_+0pD*$`P@H;k^DI&0+ zTZ3pAr0t(l=RS|tHji?t+>)0rl|}3?=I>NpbCeXKz^8HPBg3yrt_99o;QXf+ID4^@ z_gO(m9mInmqBBfQZQW%aJ#F)o+!}uILXwI~#*eGhC~nS<^v2t_R7G1MF#f6 z!*9>R>TG~b8Kmy5+`TnOY^i-Sk#Tf^qj&?b<-!7Ium1gc@RlXgE|(ZS^jdxB;LXGr z!!CyXPcdvIZ<2k2GWI=kWk8jgK%HgJ(c{5K_23(kD|s`#mxow3)I?jHt^84`^{rFww zQvXcU{tZo(@9qipWML`K%Sd`~_@xES1Q(2gO7NEYL!SNW7)(B>xqu?&4_)%zH zZJF4k2QMZI7W&Tp)CfT*eKRyE%JL~KpVBLQN_Q+}qSz)?6?EEOGqDY*lmobIg0yYJ z=Do>+U#xlEk%WI6XsP@dXoK-X=Y1PVHUgtn%bM~y-2{l?3Xgq zAvX%>+a@TjMb3LGVE(YCTs>`LI+Y8XQ86#_b=szuS|Z%yX)@4lE5jKy(Xy8*)wQzQejg@Qy@yIM%6V^8_6PD%K11sN3eEfs?EM8z z$#O%z8DdoOEp>s^HVMCq#6UH_!VFHDe`wu7uB*Bz)e1PLDDtV?wLkK{jJ(Z7LX- z(Yc$(yw_a&0Y21Q%}jf5+J)z)DV6W%W^h3#lc$06F+)(q5^0x6`zDc=k?K%M*fKjv zjt0>*q0{)-Znll?JyiJzns#HRmHa$C`~BRMLf@`~9hONhPb*D(=(#DXYo=W@?Ym~$ zQKjZ=ARA4P)(gb8bb3+5LziAWF)Q}|ife6XXt zkS(2d>9lXsX{&cG+}qyK?I2bgr1uRXc68_vvtyp1_>9c`D?0V!Ok0#oe2GCNt)%W@ z4i~^lkARbJcfIhxp{ZQhms@YS_1@&xn^~h;b|By5>9rFyHH7fme2!8l-5ZwhL5sw< z&QC6nv>_4nWeFloM@2+@nkR_pHa5?-pj|s&56<=AeA9yyH|jOogd$BrigXB?wx@3@ z^b+@MtwGTZwOROBfmE-r49KSnc+L$E-F(4uf zNSOs{=>{3jq{_4EAuWjbB)9gP7Y%!+k>6h0z#`;{@=j>-9z4IGxuE$TXeRfqmB3gN?!!{i z3{CZEQMai#b=v#|O>dvWDKh0Ds$Ul&cYzB0g3nOl0Tc4f1^_}?T6nzSw+0~dn5K(a-E{AQu zLj`)%9h#d$VC}G>7Od7-j>R7A^<`IIoPwVhp8tlXBFT>{v5-Vf^{2@}k8M#H7c>_% z-vmwN**3}oqmY0M+o1L6F#2%X&rvo$CIr;{I-`be(6Jn$<}UV?N(m0TX`6;t+QtI4O-L$so9~9Vz9N^LXtv` z<=EZ^Y+ej7QQsxpFTkRrYfA95s*mipYIIiAOR=htR`t<;tojI>A##}z)ExwShstU| zZEh8-j(&H!;1^)8TxWlb#B`}#Fx2!X!;-p&>a)7a?qJw6z%rZr0_+0pe+jU?D8(oR zFk9IbCWRPnz{sgRc?Pw16tLH~rgq{B3@gd{<7PXs6pMF@zs9nhfXfN^CMRH< z+Omz1zXSceSOyi(r)j)?J8bi8DWfK~OuNgp`wG+U!((nn8rfE$N+8Hq2Q=q|QKv_$ zjX4jcF6?F4S5CV>G+w=skE7Fkt5t zt+iFy`{hAeNvKT{=2UN5DQZ6^B*lrY#H4%}d@nV$q%!;W-5QZ(I2OleO}}>qTA#TH zbyu4gW*25(fZ00^zNZ)MJ@y#uVITuL)W!-$Tc6@Kw>)+ka}%9%;tQsvy=Bn8=#+?d zLiLPyqqCG%a=%LM-&JzIjUIcF7}#(G8Qmcg_d4xLv}>B4#~euUnIQHzbnXtM3&N3= zqWpDL>a0eg@w_FB-;T{ad!1VFTEeU)%ztYM)2Pu_e1Mfbq=BqJvoT>)3G6Z}+p&;_ zIF+kQm>sYehFul2?{p)xVC8hT3$yM+a+29iz@EKM%_-KTyC&UNOu7%hP6K)R<^r9! zy`)epM3WA^%{dcObvt%N6Q4&ie*>)0C!&7=mQ?M_=AiD9QpBEj8GhX6u(w7mhFuK% z5{A8lOL%vjF2+ee|@@2m#q70Y9oX^7MgTj%k zElnlzeH@ z)rThC2lg-`1(#~HRHIj@Mh{QA(n>^b6^7RVGJG$|pBvOIv}0*A+Oaf;JmFO>Y4_S+ zT%2NwZxfPf;p!+#*&^w@ccAc63B9E{)AT|o&ZWPH}H#rdW>bhaD~&y}aL z@>Kp?c`9SuBz+L*CJM4`0m;pQ-P4<5^CO96AAr49o=Auyrt8|ZtX<11b}bJ}MwDFlT?cHlB1lq!+C~QqG-+cLIaV-Z)i#e^ABh;EA3w1r$O`fyYyT#QeEqpwSIZY`sEI2T9<7b zV?Y_ZWMqY*wteq1y-!IVTO3HVrxVI&D)wJllRlGsf3s%c?_geyQa)0^{+E`b^H3x4 zRd2ZJ4c}F7I8w)G0Ixt$zdT^Slmt;#sM85Nw%CmeiFyp0d9@e#qX*^^G?P;K3z|e& z!jdAMhE2lTnV#pjXr+iO)o7_kuTYKdAxr1EYhE7$Gv@xcFvtHBul_u0`4mW+&j3l z4XieaKpJl#757WgQlNV>@6Ny057==(&?(pLxOve+6eaX0cX|o4KzuWII!RfR?V4=g zG}+=PO{!Ih*v~>u_eT9pn7GBp`=itjp>xmoyLx4|n{zKrwjRj#&7H{RB{>Q{51qHo z3WUEWTT;c#(zS98Q_j(ACP#2u4uc44Z5z@8I?-JsRVFviB{Q%sNKT7Mj1 z-!%B|Ms zFt@$JrO5`_3xZflbEc|sAS(9*o#o2KXE`x{799SXYbAb!5fO3(b1C%1ZRZ`Y&fkh{ z6jEGs?V4-fG}rnxn~e~H&_SjF76Ohr^;#G!qP%2fwnIhFFc4*i8r+@l1)xl=63 z&7QgKyzPfS-*&RGEyZ>zwr^5wO}F7(1?DyyNO*^~X$Qm>b&lAa4&>r~a3^2o&Vnb# z3zO}>?fk)=E>3LnytstNya)*iQ~(5Kxy*i?ASci)^wcF2_{1Rvz{d@`YlzkHxXL-_V&s*SZDSJE+Jj2bFxzoOwr_ zE`05Snb4fjdA-NN1X##EQOQN+eY2IAgAcW-qyVovJgJ4dBvZvYwrUQM8anv!VEnc#0PcBo*m-K6px$ub&pp2o7z5&JE|kLUMveouet zd-^h9*F`8e+jc44G8J;`_gxJZUe?CsW2r~SVtICp(H+3DP(w&74YjqOJL(s-< zW&UQ&w43FHFi>s#NuMa({ei6ho4g^Cb;|0eto}{1`c~ZgXblFHEqYTM)YdEXVheX& zgw|sxnz-OYO5J4jd+01h>5KSC)onY}oG9FVMOIJYKL4%r-})Q>)*na%wJz4HtWZ(~ z6ib8F#2^`)5$e**u^(zYj4676PPu*u|0fL$aTO&!QGE0gca|s?mi>$CX zA!sLuD$>EIcPVWdx*k9$Z?V<(cz+ZZlkeQgh4j;sChQ>}V!?CvNAf&qLH`_Ut+>VP z^PPRZztQLW@=sKXT5()q)WtxlR*3El+}(yP9cejGf5uyu^`pRCz6kHzU<$?8S+{sG zWaJa0QC_jZlt7tmI@$D1Y&zC0VIc%oZv#}<6(YCq=xEqWx8g^BqI@BIVuRUY#dd;= zluhEcCo*;`j7q0z9_%@r+MjHijGA+=JNLT()Lu8TVXL9gjU99gHELIj3`Gnq8afWd zrSOFxS8!jCF?$uT~lu-s~ zpg^j37|J$+ZT0oQ)n%Jwe}K-Nzp0Z2-n0$0+>Dk;8jrxfO-;1g|Y&!^pc zYfNCo?E9U4zrWJ=`vY($)m+d97;@Wsl{UcwC3sq0dJr#5I|xpGyw>%L?tDavN|=0d z=Vn_oP7XZFw?_U0Z_M3iR2XS`W2QIeZQdA?B_*Z6Vr2ncNTB%^m%>g_*n3&&AUq!x zZ~q6+9T8y4e}R}EH&H_u(c*4rxk^cYfX=(a3m3(lrG>@Li>Zy0$Skznat>plJe0 zIG|D|3zOdQfUoq5PJO(^^$YDywm}j6IoYyDZfl_vC)?-$&TppgWYtNXlRDo-oogTL ziXGgyrBJR5YF`eZNJa&(d!lo|na`Q?8#YZa zX6M=LJbP2;nbk(Nj1Gb(ptaMMrQ5-<=qe^A?U0zr^r1{%E@ZnhdDD`9TM4Ut}kqg(@`x*T=qyOF%{a1#hds%=)4Ai%}ma%pS zUfpZ8vDAJLnUA)#azX!C6#e_2^zfP@ z^ih-l=l9bz>@#`3sD@&)=vij6@|;TVuPH<#IRQHX`%eKDmuT8?0pC8P+WHF3(;@q4 zn+kRrc$r(23FOB{2xYW0#IhCf1QN&x9OX{=# zclQ6jt^c>Md$_^UuT@NiAlp(Q%yqPiu6Rh5yNPbgBV<~B?1ldveT6eWW5jGr1L8E2 z(?;Ltr_wt&3t`DQ`p(h!9~*rsdK3x)zEWvdf?8>Xq;;TiA9hfx>(A~qa-ltKgQ=EJ zJ)n@dM#1wgs4q~dBhNJJnP&a2H0xD_ds)D%2&joetxJHdg}Ubm_xL$7<%0O}=lt7{ zYjnY~gG|j&Xi5ro;Q-ZEAV(s2 zM$=}Eq#vMCxm+`@AO1?^LVJK!v(L4!5vgfX@@Z81+$?&(MM4pr0b(;i>`eh;;$_q^ z8i=QYazhBK3Qm$#lAFIpV9N0k;FlI~WB*Tirmf#X=D$OeH8gJH zEPG)mW!jS+(JSLDKUXo_t#UOB(M0A%=9`eITakTtgtX0%)<=aJY%q!~KANDe2aYUq z!F-swc_mHUJ+feYaf*tjv0$Dz&OY~W-yt)NEv6rB`qAFxM_Y?4iyMT-_R$;x$)?bw zQ^(d;ELgaQgsiIK3cWCNuNYh36Kw8*;r1|itX}Q~T zFC~lJGKmUX6nC~f&Hed&JNxaVDaO-HHr-_ZmYYmyEz4LHv`7UlC7}&3z?CA`m3`?) zx%Ba&bJNK0l(3kW_>{mCDlxk32Q0iqri9Pg^ga?Lw&UxB?1b!ZK=udVOy@2!22k_{ zx@3nKJzz-@;u?J{dK8?Gzo2>1y+PNCe&&c3qAhlXi=LLH@QOgF%$A4Q^6)z?4==0W z2aTv=3v~7ZI+{S`ko;R}qtnt9 z2%k48-H*S?g0q5fRuI0cg3z5g8x`QS2Pk)f?B0Mhtd+hD9mg&(e4)otVzJwDCP8lY zKX4XJm$1NcT9nxH3(U7=QrR+JCNw8Be*u~=kH6R%D@KR0UbC7+NxmM~Sr44l{($Kdkp@oxxN{Ct@dJe*v*Sm~?BeE3qbskb}Am zsNO1si#Eh2U5{dupUN5bE;GrIx36h2+t$3qc3Ljy^EK}`GWA59N7H#U{f(pP%VZkT z+$9jWqk>uxG#3P{wQFnHv>iL8^2g8fuYfJP?obO;{PHz*M-nyR)7X@rXDWRAnmQGq z5~L|XdXognjVjhvfdd(I$k-$f0bZ$Zp|LIfP^bd&v&+n1*pyH{zourzTrAzrnsi^0 zAd#|7XijLp37Va=C5geZWCPV9(2xjZXSGRlE`+%F9-f91{p1?YZ*CdwB{J)&2b(eyWtra$HT6sZBu1R|p>pBx_b*v#jly5luh3LjMZQ@*xzw zho)ac3_e)1NYN~$de-XJ4hNnPvf@lUnTaRwN<2voX@&~ed2AJE6{_|MX=|f_jTbr; z6Grx=vru{e3`#6t-P^q7EMT4o%@>SlhB!4vQ&aRCnxY@fvn#WALIcDtS7D(FmCV6w zgp}3Sk;iT-&${t9(%ieL5Es0a6Pg)maXYc+_mz1zZEk_)7U*4DAZkQQM!;CN0C_=y zTD?Fki>y-J8XZ&O+LP4VzbJ7?Y7jZ3#&zdbI+4Eg+k8nUU7<2$F^Qgph|rVH&& zE;R1cY_%1zF9tfSL3J|ls9HxQTk+Vf(=YT;h#+y%z10ws=FK8%qNE%Yei}0EFftt@ z=a4&x+&2xmtqFEygNTJesdcEG3^>@=C3Des44L^6b^AADTJD}YP1HZLa0%H0x32Hg zZk^Yfh$qe{128xlG;~l6{K(OmB@t9v49Pgtg(a~11Hmk9{)h; zV|#Q@o2dSI>=g7urg|DSU!l$5oHB$dLwJ)6p~+Gyv;d8Dh0T`?t+4>DMq`nNwj4UB zh(9@~nCu=@R7F2;oe?TT>gV;YcstwR-op z044>fxI)!ya9A}H72$d)D#7$&y@UQODuLWZ_(q!|g*Z9lRV%Hl5DXUuRo)V-aX>nbzP459*e=NIf)A2RbVIN1 zc{v3GZ@ZwB5>bTYw6Qjy6X*R{>qs-nWG0#XPLjzFpxFhj2Uf@k1WhYYsRl$0X|-vz zPUk|?F0_-eX<4G&ph@V+!Gd<$Hi+nXLH0MBwMgL!&I!&pfpZ8mv#d~iCa9JURjq-o ztvh;kmP6~HjW-{Ng7l*0f;)jig-Xd=pb(+6lM~x%#Q7RHGkNNQ{!v}f|FQR_w~;eF zw-FKGPL{K&P5Fm#A&=koJRVKA)sSxwKGY9|aCBJYS^n>X(?*>ZHK6ppyKK*oFIyCt znL~UsC!ZT?{o_jVSLQ5-yISWkx%pBEO9?YXzU;zD^jKv32XmIP)CWs_@G|v5oi>W} zeWIlfYF?qC2ox>UC>;GI&eO-4kD4ooQpYM#GGA9 z7tC!hT`^GX6Dk&h*;ppw)Z(YK?mIZ|==OBKa^iua)`?60HrDP&>(J!O#O_a}P789b zJLkG{zUa=`>KNTh1=Kn~M=Dg@HVEAP)>(0Gr%as|58j+s4jYkF#N@UR3YRDndR>P@ zJcj1i4hJckxrW*`)c(X!`@D0EOj{cQEnPvkfl#UkP_dBa-U#Pez~1qv{JMM|r3w|y z_-sj1MH0>nt)7pMD}TnsoAF8&TB$-mkt*~wV0$G>-UxJ40~Jiz1DIhZdD|p z8)>}ZLv7I!!&-{ma!wqRjVU6o68`yP!TeXiVhO_~`&+WVpOF1M&9Kvuwk!sNhJdAr#DgY7Sq(dTJKOvO;y%VkR4$H7GMU%Tan zQXl4p5cU{c&`laN_X_#&OTx3k+zR>&bzWWP)qm=|$_0JrF6h?wv=koDMyady;|`(mZPCF$-6{okl- zMLZ-7FLQnSV;$jF!0ug$EB|lh|NTh*-_y(AF$z;F1RmT$TNbFY#~W$mWTQIdtbj@G zzfJKYHt@fIbwQ-x)P?DL47a>m`isRD$1aZj36A}SE+2VrOcT+QvH-gP`!4|&Tg9TK z!d80+6%J?{PB4*C6PaDlF>F3!*z(cc{ROaL`5Rza_xG#Hb%1^1mdZtJ`QDcA?I(P1 zPXpE@Jf!U&xSF7wE3~nj$wMe{bWuLH5iXC!56Ary%F21Os=5b;aN+9!`#AIStKo)G zGuDD>EtvkP1yc?TnIoVwmt79LK~68gYMmUBM(Za5`{0CQ9|zbkfHe~T%+IF6CdSHF zomcZQ!+r&_i6PQ%KfU`(JTe_sBOL~zmNwgI2O<)o_Xlw|z&jw6mcfGZW zXL$1+ocC8rYHxOMn4u8;w9)XM0h*=o(Org~!KOTh<`-4Ii9}g0n&qPT2^Y;bt}-24 zw22HnbbxYe&}y0BR!6CGD=dBrnf_ro{VQ$en;c|5I7!g0;*hW)AzI<<6od5G;`YbM zG)lw*=K|-8z*$u}x5~hi5VXmz7*v8yr<$Z!o+s?$@8HzCv}t<4Ykx05MhNN@?I z%if#cnQ8w3ryA2*>8_RTPpovm!JIUGbZiB%l@98)KpUixg(-!wl)|UL8IN{B_>pz? zg*k;4e-j(Ix|)-e%fR_elo{LF2CZ$-%eFy^gwukd79OBh1zKjyazhYxmly#hi;dU&EX!6(!k##!S$l4N6#oW6nN!XvisW zn!MSaRjuthg`<98XJWeP6bQq!?2hvb!TCf&uZ1kv_i}yzi0k_s;G|j{H&Mv#{lvL1 zgmPBMF)B$SX`X0Pd+%eqH`dy&NjQFUs+F52fiP8+G)ue`oG!SSb1~}QzMnQ6T_*PHW2 zZ_e7RrPcuI$)Knc%H+N3&@-gWLVhAE@Ex3TcdQlqu%~@l2I&eO< ztu?HX%eHP(u$1sN2iJ;*Z{3bhS*v?_y|qMfjYegm9Dhp|PnZ-;NElpxa#lX4k0 z~UDK~rZ=4zDmg8z`ATF{yyw8Ec`KXHx9np=oz&Cv4vr$pJK-kUou} zglR>^A}(xGduCVbimMZ5b;7);6Q<6tvPUY^kPbRJK^5r`w5d<>to7Vb>vt_GwqH5v zXjeh1r}pU^*@-r_ z_bh9MEZ0{8E-BBrO(u330Nb3yYbp!xjxTZgxe6R5}rI?9ALn}Xy}b{Ra!xiidn0DBbo zm!W=RQ&%!8h)kCO_L(waUGLTPUj4`3t2Ejaem}@e+C44<>V7<(b*A)fhRm}Irh8R~ zzW{qM{wi|nO$_KpR@hDWr3~x7(!*AI*uRw?wzbZ)utKtTP{n{&M*{VYvg6>`PQ?9v z2eA4k2hw_F)4TyT5Q&Q++EpWQJies<5%(9YxklnO68}>paZetsn}bU<(3l8ylL9fM zcj^PXpB;%Gh#%t3j^h3>?9-^`PNft?zm8!a=W~8#SVkdP47(WipJG_lEhP&>nZ1El zL&&Zbym_VGlm?$2iTO^N(fbL9@K3;sGwJ8e71@hpieCoU#|--wuvlDd2?>{w@F#?X zPrqSNdLws*o>4#><-R2j2uk0k_h3CI%a4zC@4o`p4z1u;6#2LKF)LxANp{@{=NZpT z=z{Em?2kb9JMY!fx8XBD_9LrC6lk>3-U6dpM(T!n5}fz?58oF|cqGgh^w0My5sFfz zm|u5aJuNR}BrB^;c(n_g8vakFGgjZYu35upE}ogtF30+5j6;u)FCYtsLZO(doZ1q7wW@v z&B69pg5@&<+c^-E!sRN!KBEWL6kmhx8gzeR(0%%C+H`JpYXlZWKxuCij_Q!IDU$Wf za(4XHN8_&^oomq9ZyAC?nZ{AluVUD5SjN8sRxmBs@VkcJpBR3h2CUNN*?RzH4A8z! z$TA&@HmZB4S+uhZYxnJN_QnT*B_sKaE@ROsY?(*9BzXp~{1~wOU%)CC^VL_n`bz() zzEbj*C{3YnyJ}yjKrMn0##>bxrJa!o+Z+BbAp5U)%|nNrlSka1uzLb%h>9Q+Vk zK8u41)g!}?&E?NI-|(?C=?`!cqA%uL%=seboMVhODWIwDsVpU-j1&;wb2zOQ<8~69 z_gb6mP4w^?s$5h*_eSAZSkdz;Z06&k_K(ZV{)p*L7b`U6Ny6>I-hfG3tb2Lr63YvtEGgZD0v>8!+wKc7_rWds}sZcK^19;;A zwXs2qm>{^ZY{FXWsexAX@oSR~Xw!(L++Lf-3yL|*h1fj**o<_;MVyN`UqqZGO7?UD zq#2-L2BnVu?P-|S6z3V^nZ1cU5(eQ%FvEYbsb&$kkv78%Ctrxo@)(-&1)5HTVGEiI zny-OoU>jQuhY%^Cyme?cIs|)B$!XJ0M56raV!ER|@HfpvS&*O_-e}V_kauicCOojm zv7TREn}igydel~r+N*lhxXB2w6=H8`(h&~HMWG{RvTwxJn{&N6U-af2WKFDZPzLRqJsZ$QWgx7xjaDbexrLB@gx%f&=TW$( zT2Z^{50a^*3CneF&d0p@$D0$GS3BBjM|)K}nl_k+_ zuGst7_WTW+`x)gxeIWRIt-hI&xMjJ_BW927n}3{9goV~RXsv@@v<~u_wU@Sm)ICLL zBZ1ZYe6soz~D_iBLsP5q4zSaY|b_^k$*(7kwgx$eaIoDF6FO)YRPaJ~kd zO}CtdHmErqG&1+jv$-p5_lnW%)J}P;Zx*n>j4ZJ1^(Xr$aNRHZM6Q%z^_{dV!K0(1asrX3H}< z^7dx`kG*TjZ6(*CDIL*?c<-HBtTj7s|sG}rWi;^F!DrQAQS(0ecN zzrVXEMbNJ-5s8QIg4^`7KubT+^x>zODtl-OExqm1+x~{$_W7h+u|O^i1IGqJ>Ch%_ zu%ASE7A@3|sc`*L?n?dCZcbWd4Z21Qg=?0KNIR?i;VFSUi7db_!2VT$)h$(|HPAj3 zM0rAE6PTTiG`-2dgMj7xrx?6h{cEI!uR|6~T5;0i_S(IbUDwBWeT;wOWBdbBi3T;* zT46>BklX}nBZDSAvP+XDhjOSj9({rFBDY8-R^)$*7%CUC>yNI0e(1t;DA*78mANS*0}J4#Pd3(fNe z=QAM+X}B`tS4RA+GU7=$OPm6X6d+Rql0txbl+9|6-jC@R;(^3S>HWc{!C6G&AL&CP zw!2#5#KHMgMttOAi55%r8!XWeR!-eUEo~EsvFql&Pl)OW?xT<1MjP8PX>Po4l-~_b z(VGb;M#cVNYANpN$a-eAHXR42J1=qW66d~3oJ)e6OrJ0$6J%_=sb$Zlo>tOFndS$A zsBP~h!#nXqb`iO$n>P~kt5+L~k)Sb`6I0@!2~tp{1Q&PYioMa#2#?|*Rm{Je1*s;wY}6{PShK?+Z6 z751)Z>&Or>WKRs6P_ZH8Mq7@in;hv}vA0@>yBv|^&6ZCt9Dda*D5r2{oEPS&kCRV6 zDFQP>RzCI0r+!sFb(1<#vBFk7L6QS%;SN2uZ`4}UJYe4bgUtJZVSMwn!Uc{0k>!_Z z$!VwgL!Zj>6O6?VEq>@l{E$r%nOwoi8HC#gS)8B2+nw^=vTF&oS>5q8%Zq~p%t4vwUv<_9cj zcEP+GPQCXeUFcS;gYTgy|A%H2Ev3Ypg8m$_P&{5hv3$a&u$I+@w7QU9)rGXp7?Vqb zO=bsaE|4)2ifWr)%6DVv%Xxh1nLA$ARpcVSnTavpK(kL_oOpRmbAbxfa~A6QzS#; zg9r-4l8)-9LG!V~_6sxx(-t%rG+zYGj$73z0py#4SnE*P4YcG4%n@5V;PiY`x8vQZ z$=^Y=pu@TG8S>W2z2X#BoWkjG3P0e1dK2WN2^+-(2})?Y+!iP4 zNL3m~+CATpdGD_2J4IV=@IYdmewFZP2wM`-X}jh#Lz5L(O4v#XdsRwU#7NOrptrgY zO$?|t8Ax%Wm2Pw-CG02Aq<0a~CuoL=eyo~S#2B;umy&}|(9B5Yh0KM_7a_CcR!1`d zFG(O-0-8>S(lwiosfQxM{vh*C>#py?xVP?_q{4a~nv`LL!hUOL;xpe_ek`ozeV zG#4@#GGBzuK_d$Z!fdmE)Cg$38MIkjj;v*r1CErp#GrC_(cE>lx4yGZY9EWHyCCIT zanVVO<}>sxE3Qp*ZJICIGzV=pMhI}_0dKOPYFfc7NmJH}K=8#M3vQT&2-p<9;| zNr?{y?T$@DNk0vmPkd)1Y$e{V#M>7o-fm^nsrE+tRFI7;wB4K1TC+YRhL1zqcD484 z>UTp^=smCc6Ebzre*PGm7@i*IrF#89LHmURDn!VO16mx=Yd9d%Ox0PSZoBQoeS?}o zFtIkD*2mVigV4Mef8e`J@0Pe-j4(gwS&zt&6U&dD`p+uy@|`T-$%}j^)Fy4p6}pT7 z;W;442*xbjJtvDDBZ2m|>$}jj+n1BTw@m2wsTpBNPJEuY{h7;&i!Nv`Xub%V5}mwj z0dK=Vus8(I4qQf*Z5xBOV{!w3AU9CIuzj7HoFU~Jg=w0h;d--PMV^_O_V`1qpP-4J zw%nS_t@$f%&8OYf)QWiR4(&~_mqQ_Y8PG?=Zev)T$5aRp0h<@O!3`-=!K+csL|6=q z#A$$ita$&N1dqh-%Z#$jD8FGwc^a@=3#$Gy)ohgHVhB9I-D_Uqp3%w{>sPWdNj|tO9g3OMPmoU`jg3=n1vBLnZU! zHqo{NVYWYkX5NIRp|M=Qxh|r+2|N9)z0{8vG*C$Lx`D16=x^LWpZ?~e_SthYXpIGA zs}7a3LJmi2$T{#ZVDEIQ`~mC@OPM+3<=au>O!chd@ZX)MQ*rx!yTWS_y z7hwM;z*bf#whh{J1d%kT)eA7br z0~VtcS%6)D{i^`$+lFn92{FV#DmJLpC(K!B%0yH=daB|3U*dSDhW`y%N!5>(1tST` zC|ORMu#X!bzR*jNx>6Qa%EGUtEId77x9(+hGiaM8NJoS=w*qyH2x@(EJ(Q2DemCjw z&xE}JSi^`9F@#&B1q+`RHSdpg_n)KYnb}zuU>9KjD!^_{gZhBzx=+|GAQ?N<(Hhkr z#@nIzKlKN~LgAb4QVGGh0#?lk$-=Bbf8)S!xrp zN-%KSItcE)+e!sOGCkG$$fJC)-kqi2^ely&$(3G0WK>5i|7|J$moVK7^CeYUQl(c( zmF6gpJPisD-SrR-HJd|vqgpBt(_@zKT_^ZxoZh zL85HXHg>4fjZ4oK2a^PU0N9%$pL@CP^_wf1>}nZy)~!VjZ=idBqpk&XEug=#fIg4c z(hH%-kA zDV+7Rsri(%#bxCmt^A|k$Upi4pPN0M(GoPXfp86I)EwBhkXeEP50s7irO>533iOoQ zMH5UPY4)1?8PqLK`_LY5XUall9YNO-^hHO|vSlxAZlIGkkiBdox+Hkhx@8RB%7F~B zH)P(|ClKF6rc#!?RvNnP|5+|x&RRA7@zDHyX<m-(geh3=Q<>qTxkwG9J5+D6rolp@P%EYR_x8ELwP<{FwW8k$x_H!cdZ zZU*Akpz#dI?5M%pXmsp5tB=(1ar--~X&**y4fagEEl>E*_*o2FJ;196_+>r7?8Cbd zY`u068VP||AfvakA#df#>BKK6m-6Va$v5=2#`1PT{4+FDjoqB^w0M(zJT&tYG%btf z%BNrX^e@V%ryM0^V+i&M5>60B63hlgM7WM)(9{dxotpH2?EV{?ETzy#@=yl3sQGF9 ztUVU>eL0=D>oSln1KFz#WSSy2xPkQ6Kr9eqPvKtnIna^=y-E(GeTzVEFswHa5`yHBFtY@0&2zLof=-G{ zxhn^fyzq^~rjwQU_|qC@nnj$pZvNm;`^9=~A)-qTzvS@0A&377Nvpn9!w%X8gJ3!| zsR7|Wv}kOS$FTYTb@HI_-3#JJ$WW?_vl;4tiOuo_n-;VVDC>aoq65mDHadC$yA_a# z+-X{ZF{m`g=~fPyQr@i9_u~2DB7Rdw8@m6f|Bp>9S%g*C&l9c&JYC>p>v`0Md)-P)~R5H>n^5sh*lIjVy{|ipKOQFDHr5tW+zk8D_M&r zC`~l+)w7dA79+G6p%*biy-Qc237*wJS{V?W2@NA_w!Zg=9z-YKxpKxucm0qC zMM1@IJT1E9836*ZmnC&yQuh~0-6tzzRD#%Yf@nbqs(XHkLMu8Ei`%w6sAl(gtlA(WVE?inh!4D%5TS(W122%<4Qw z2KhVJ^Bpw5DeARSn64jMOHc7AuBUZ1JSJ*C*9a0C@?wG(6Z9KQ(9;1z%z?pKp({Jc ztPGXefXenJf2ZD$%~HP`IUV~y7;klzA*TJqY;7oxL~>TS$`8ybpL}B(>Z?U?wFv%7 zi{R6E9qLwwO+YOIQueAcW(QN7NIh$-#~35O;2odm+kh4OidW}QzYf^gd(u!-Ps3|G z9;WQ2dt^7 zSn_#*eXa~t$^z^H>|X`gfm@?W6OiPsSbKw7(1FXSjN&p6uds9{8SL8?);05Eh0TJ= zf<&ja_dYdYIaiXxN0P$-*!z~`Mtfb!y_|6)0w4ea&{BHF=d=fX_8&Lsa#{7uvgA)! z{#66+fRhY>iG1t{`!`HjXSE^3u$p>7q#<~j0-U|6Qp=tW`O(zwU25X0JWyQ)KSJj7 zT8USkFFy;g-{71sCv2jGyjAsERsR#J`iEEINW&{ff{fuHK?ViKfDkHuDz=mlY3)~` z@9hcer*!SKswDgYSaTM)?3$ki*l%PNU6RC{MR~8pdnNv>R$`2HEU!5{9h+7V^ z-9XA7W{j2OhBUb+K zthr?+%Hrv17nu9}(5DMbio9b|c1+5T#H2h-=r*o|l@xkfiGac@JOvqQ9fKO8&3;Uj z6sMGL&Qdzz)y9@c^Z{74HB2>LYh$DAX**1}!}LWC(>^kdSee$?6vSEAnKXm8Xr^Lb z+A%f5??|yPsoU!f++x}69C2-|NST$N#oRsu%|z;3kiP}_KOxBf#+o~li)&5L&<04Q z4t4ekMVn~U=2#9$@BOWU@Sc?S8gHA0->Q>-K{FdtLP?W6=XmWWNuql|NDx@h=s#I73rBiwiyR{BqwGbMY??OUygZbLV-!D9@8cNAKOB&zwP~4e*&V z1Xr>^>=6f=M13`h;v<>`Mf|fF-&I%haC%x2_BV#+C&q{~+qQ&nOZZP%!oR^7d9GMZ z1$r$LBzFYQKA=ZRS~_93V~kO{6XvP(p5|}?O%nApG)*LFvYfAcKp%tVeKPmcK1(j! z{JqWJKVts=1~fbKh@l3pcmZiLz>5bAs^ZycWIguPOeelQHSr`@JT2mw(+8QWW|V`o zzxd9w`?q)h_RIRWoAa2`2jrl!5*QSG=9O13Ho~<=IiQdK4mAC0WQrIkJBx5NEOU_f z)1Z0(&T{$Hbdt0$p!)*)q6=uxQ*e$3qpXr&%M6}Vft5c!Y7rwl;M{&grrZwl{EDB& z_%r_6P1z`3{MF2{hvpudFB+QE0=Wc3Q5mp0u$PAg0hwyAJUGQX2u;0xI>DTOefwWLpVPt83wUoGqA)l>^ifdrYUgJjE4XK66FW}>MoaUkq(^_<3IM|Ogi)>V_RgO?c4Q|?TjSkketX1*gh_#&oS#4UZWK$3MOBsf1UrdkevH64w1 zJ>jk={E>RXhrKAmrF0>Msv00~Ex%m`WUn!1W{-3r)WlEp`+s@kpmMEGR6^*FjD(ym zC$aQAfzTtP)R6Wl-J|qHqtvN4!ZATi90XTNA5np@8Qh4S>me@+r4!Sw59mtRyw-u1 zg!IhXnvf+8`8PkHpAISsJ?~k%XX#JO((ll=CPb+d6cJg;(+xsf0~)Cn%YBS_AVBjC znzuioAN5L?&@}NgH>8}CBXN2fH1BV@7tjpPDes}VhvtihCR*+svqMg9AUzi-fdX}U z*ern~4g?GNiTF+l_xgXz6=ag(xh6?%MNVUWtrsOF^lcN{HnA7k#A-{`Q4zGef}|`E zvb@!5t$X3-M>>7qpeeU)Vs;Y$49(=LQsp-^8AT&l@-^0$9vPZUclTNOCp1;UcOLxC zgMU>XyoyWArEt$Hkc4P}vn7a;8aK@7$E+xH@1CM@6`4wc=k{K8l(o*v^8!g8_-Rs5 z>{I7Hb-w7-nbD#(b!c@7gs2s$(j2(1Xe%!X2OolFKIzSUR_F`qUWlB%)j3D9EcQGS z=plYK;}*Pc!TXB@@3mOer9DVI8%P}pE(IY;>Z`?CSn&unMeli0?8MhdAY?t;#Fi(9 z12sQS@Q!z(c|iiXQ;JOjZ4&53BoH^DQndodG!T&ip~R3@FW(q8yC3>#E@a-moY>WL zX{GGva(l&OYL?UU_SySC%}ZoP#-01VbKhT;`<_e7=4N0`Xq5swcnbrenQH6KIUS;B z7cy^W)&6eHzL=RL8P6s$q*&`TJx{s!05UD({%G!x=8Ha>vs#@T3c1t*B6GDHAwo5* z34?LUAt#FRd#d|&WG>a-DP2<=U{*h?4YGxbD?SgI_dl8!Gm{X}Wv{b)oqf?dTM}Ef z5HOIw zN|=HJ{b>{}QMyY6eL`pC%&|Y5`@{L759dT33xhB@5Tta6vg$hna~syk$}uWP<)(-> z-cFlW?k9w}D5x_$$yWSiLi<cRuZl@@bLgY&JSL6N8MbP&_d-&23`O z)B2&%p!@KYtMF8|_~X3kB9U4C)l~OSzfQrFc4*KJ4SG>%&?t3jUjjy&%YM=XN@)R^ zFeHXspNE{B3wd%An*OfmyZCjI^V!Ksm{UraoS*pXyiW;z{&lW8{7u(xy7onMZ81SZ z9Y8DrA~+yQLCD^w_e_}5(Y^MT_#jTIC%SgxOpNyN>(q>nf@06}Z9d>Yan;S%ZnpMS zZ0#g(T^U9ni>)Psl3Za-ZB=@!GU5<2^`-+QPW**8Od`|ykYa3}Q~ayd)}K~da@%bv zyA9=4Z73);MPEMZE(|g$L9r=dSi84jsqrD5yXwv2&0l2Dl^bVBc#aP)2tyf}ou1aY zKzKi-_A^yW8fhO=_95j(hm@g>he-gUPY`Ya-fM+sGH75$orhAr0QEo$zf^BZ-QUo8 zZEyx={1ctd8e#H0LG6R+%o1DezSZt8QoE;Ac_y?aLRiW@nh?D)OpV!$l1M*B2jzF) z^jG>Img~mqWSY+(PUR&+K+MlNqdXLOz$*=97m4j6u~!s{C5)Qg25>}Kb2CG+iZG*# zlsWqJV_U7A_}*5lSLUXM=Je57opZu$mgH%Xd-;B6wOtH4dG6q8NNUKhzaHff($F%Wwhtgf4Lf5qM;zS=U4VfZkOPbQtChTF? z3awCE+N9AYjedeO`dHP`fy&~T8Xd8in1m>PgubS zBunzNm6#6$mS|DU8?YO&e-mJ5BdR?Wn3x^JbA`&Ifu=#Tb<3#7B6)$U(c@rs-`b4usVq#Pa;Zfeg0Y`%Y6y(FCyrCs!}iynTa=;7fBJL)XL ztpO#^Al^C@7J^7garNe!9A$}bMWw__Y)IE8tOoPPN^F!(DU$HhChUFE=@Vc@e49$Q zsq{xor4IwvwO~OE@L3teib0SJ5Uzy@Q_|buGXfup6*{6<{f;jJoXNBS2IOgz^AyBekVOphPbGs;^h^8!}PxQilerMH9t@gwWhRh&+bO>HhWyF?o6wU`i2IGWy zADdVGHlfKrhN(-Cdcx<`8~Xi4_i~s@Xyz^7-}3#Rknev3nzOl&rUP<}1X5>*+LM7> z&Q)s7&IiJ? zJh9P3(3IFyb5G4zO--Dg%M=F+nIPU3YM}-`NA}(svm8*`#|iC(x4Bz+SN2{&GsRoC z!*6K1CRgRxLNjOGOweY6Uc>}(c(>6zq=Es0mZA26(90~Y5uEw~o9P=g^`>i$zbHB6 zpg*#CRmssKp106G5Mn0g8<`uKFG6OW!Q2N!;T8TFlEG7}z+;6*hm6_|$cN&zx`A&a z6Hn>dSCgIjyw3`ep=&%ZUhqCgd$G@krL;55c81xHWSD*9rx{#oFI>SJFJYflC^<4P zr<$o0<%1NhpETV;rd$yUX$sRb2_&Y7Ec`rVJ~A`WHZnIdUxdsejAWc4(HyX9S0Jhz z%rUu)RlIqm7dTFY?`O*|XJ&dYiMc?gWJ>3c<~mvgiR&wonLTfIcC)iDVrQ|g5__BA z(iH^LgvcZyAyTr>qVs^bHcmvRblVClr{w?lKmX@H|NVde{U7$OCAX2D*RF^FN%863 zluD`%-2DR=O6QByj$^xw^6wtV1J7%4K=JTAzRyfD{zd_5S~v?HrZ{-=a8jldbUH!b z{Bx|r>#XUY@t=N|d%(A4WmW6ELY#!*F96{o`l2hTib ztrVUo&3V#%*GW^Un<-$U4TPB>`&MAHZE349>b65dn*~RVTsnTt@|h-JJC(8L6Ohk zlS>K+-OsOC&hkM59e2>&otvA=AHt-G%!$l*AaiZ2FDM8RB{z1szgNWF*33b8=OyiHO+J;2F=8vHzfu&t5r=EmRuH)+6;}=r-rAOY1^E( z&3D;0M`wakDrAVmNPveLu|Z!q+3H4)zVB@-w}kG5C$Xz_zG<%cb>$?C@k^#W44rsC zUHa$nM5LU3gR^h&6@7z`==LJ2)d;{gGQ6k~R9gy^?uF8uaNCDYJ>l;uL1XizUp7x> zmv8V?6Dn+Sm=WcnDCtXhhA5SJRGCMWHyu^h?iDu=s8RwX>H<|Y0k^FULkLsfw|VNV z;?Dt3{_Sn+MBj)Z%2LqcxImKUR!_0eIX&m}eAD!d)!c09P;~@(X$z=h|MWnv*fx#6 zOO2p6Gxk2G=at}SLPPX3GlZ$E!sWP762kjZA-d2CQIfIFqvt$&zUk<>cvW77peORE zHEK|83t-P>3&O^_Pm*AFR!_wfUs*k4_$I%Ippw5sYon8}P$}Qx zNh}etc3yv zF=36Qe9808gj|IV++m+#i52I?bzWRwa&dir!lr3k*MO4JLDU3-L!fM%OXP-S+qc8U ziEb7u$FYb!#Y~HQOU!0SiA40`7vR~VP|HP&5W{FWRyJ(*pf9lO+d@2G0b%s zRC_=R=CW}r?Q3MxIF;M}@$0=WmM;7?VV#gIDA;t4zUILb7_886{!`Ji}J`LEk znnIosNkcEp3855Fwj$hFdKm5kY~E20i=N6A;Y1jtecfRRi%WXJa-8i3?`wyDxZ;8^ zb7FR4_7#|YK-Z5e)`l{&%rHSD36cn*x7s7qT-JR@*Zh3m{yI+cBv))V8i@Q=qh@Me zOcAevQ=b{9w!0FBh}CdrJG+_6>9YrsLNKoMBkHoPk2JU z7tlhVm8E|JmJm(81+<_dQ(C$mH&5@AOh0t}AtX7oL1#ATo3cUI=CVX}h!z`2ra%rk z)81F?>teE z>xl9_F8|??*xt*@naD)bV>3NAukhGBFgaUr(xL{~q=7IgWOs&ay(IP$g&se<5T2M$ zczf-Xt9J5~$oz)R46)=uJ`SA^6(Qp@G|iZegO8h<_nF!s znP%=XAGGs9`?d#dD=b@8h@}OHm4s#F+%Fu=RLrtJcoJej%Q$9^= ze^1S^Yo5ywoxP+cru+|~c{w#Xh-a?K%vE_wuF4}MEpyRS1l>yi6DnA%1uRa~3oeEE zal7c}_3}o73Jn_Q>eNguat>r*{fJ}m!!9TfOwAwAbSXI>wDUpxrU$Jf6&#q9>M`++uAW9^ZwfD?$V$G6{(Pl)47hqLj~P6{3v7S zQ-IZ+{rj_j|0VtVPXl(9UN>9~C_V!3jUY=d;H#~51o-)?djWeR+~@itF{hr{@6s%(fazlSrCG(kqCh=O^qk=*_KxhgXnJ1fkI&v9Gl! z(<;6bu($F)X;{y$dPR$3Iq$IILa7I~oBDkp_m3wr64LB|njKKD=zw~F`K_F(xs6%6 zDoE3S*h+!EgnR9M#rk;2!b8xE&pN1!S(>TmdNxl%AxtS(p!wV^-5+*ejM8Vq!c16r zMZ&_YvfrzdnBP^Oo~BV1?EB3$Q9>Tx&uP z1FYVkr5C4~ES59terDbOTUqzk7u~on;EDzkCb0M@L2Wg3B_!p?+hoRojT7EpR_TOS zeBCnGt*_WIEk>l{f^ryM?=P!*fmbdcL1>d)n&i?yL@s%+rC`FEhNJySp)v|=>V4JL z)7RLESGp~Q!0V0}MV4>mk|!gU1Emo6W%oaK)hs&6rAaQmf?RrFlsaM$?+L5b1PK(V zg#>u3y!M66%0AhBocKmW3Y{dbHvNmL_<59CL07ipcwfB_&C92+k`aZgZBMWLa35aaO!bS-zQd8i7AAbLWqA$ z2vMz9=EXp38$F6!f#fVuu?23tZOhKPYTUc4{+H!&v8t9orG=k(H8$q>pkfbNRrk+V z4fSa_orcp_7*3z2f-!94Dh*sJgRI?P!NsA~W$PJjtF$Zl=q_F*J~IU`@G8dn6~U{T z9PUAfNrRuktB20h%{<-wTc?{C?WSl@mrX&e2P_3UM9;ER4eV{7GB|FAt|t;8u`-uILmNJkS+ujmj+vBiMj?--#bdn zZP7lT=$ZzY!|axZ85NhM4J=WzE{R@t4`wMR(kb8n?z>kT@!=D!;YJp&+M8*`ZS?Aq4^$Y zYU{0!zO<%{L&lI$Ll`#NgxAHi&^|?Ap72Jm;fEqnuPTf<;tWk0%cevemxJ`ouBkI~ zcV_OsFLSpW@hy_T(0OVXXep81(T_8T-sKTFj9hNd`^>wnPH@Df~5 z;;@U#eK*X-MTHPmr&@Qab^kH7?y4Fh0=SG8{%mDHmq$6%>bg=>Uv~obb~=*SRY{;) z@YxOH5=iD$j@v+=n57{()w)xy`!2Pv7Q)tppy(7{&j zs$D#D1MysF=!(UPIv!S;_5d_5^XoZ_#C+z?XYQMxx!$>TB!xm-f}pRE8&&Ast5MIb z#J)_y+s*nPCzWf^6i30YlZv{rMDd`*ghTgv+e_h4N=({z(zY+5ZJ!qURo_(lg1|WX zCRzwAA4bw%M@v&%+p>?$&3nd||Mu34wNxYY>y@jHE~LW83H|PqxtDk~cbk)RPSRIQ z(&zEIDV2>Iq@{qc6{w~H%jU{hiq&PGWZ^$W!d@CFH2F*;rPCO(bliNs-$#0ZS3)M6 zHT$z>|0Om1PXm@}t&P?ZA=nlW?Fp4ugae<9ec?v*B5pTfA^F zJ20T^zQ*XsuIgEErmD|2 z*G@9(iF&@4su31r&%`zDtk8Y5J;cg@oOXYbmQ8|QiDicp0s0eCm0NbY|LrhM+Xtpj-jJ?`>BZV~Epy;ThZWvwKL1@}tA%ogQ zZzSEb;aiFJFKBW)QY%wfB>RL- zOOptxn;pyg%y*`|L#1-df0mT;Nu@=+V3?dIJbJuFx}I`{NpP85mdWKsCKnpL%}pIF zaqd0*{a4FV8$?qYIUccc(*^O7m76bmYsw8{{d|BL8cQ&q2hGP*?iXkhrY+&o5+418 z@aP+?*^FlGSir0AW#6Mi%h;e-j1cFsxvq5bdZG^h@ z18bmP(7Z3qjf>z7Xr^TO)XeYNqJmki+FiZ@&Dm3i zw+ge(J!~@&Dp3N*Xi>$tJP1vB)Wa_~!*R_s^D~CXg-Jv8Jc-Z~Sto|XE4*)o_q`~* zFJmLyqytm#9fo@h5n6?$!pLF+w`0c>d1Pmae?XJ$GY8jAv7i>>|KULUbqy4}g63Dy z{Er09e`lcW6MLFK1|jI&DuiSQ!od>A=y431dZGK0gS^O%h-xb&@_9Uwa4A{RPh-tz z)v@hDwYB=(+2Bl90l|m3b1E`L4^ja+r#1Oqflk*9Gw(V=5 z&$p&Tkud(BrkY%v@hDwqHQ#`{jOQY03Bfv zeQaPd>a@%)nGQlz?rLaNZ#N&Qr+mIO)flPZiz9FGt=e!6v}>S!#Xu`19B~)TQZlHA z?RC8dnnPx1>t^F1H0|zN)A&7n=xU(lF#OceG8SYcekp4f@fCTyB5!{r^7b2VO|ilq zwF7RuS}$aS@Lr(^Rkkc6$FU7pUxBA1BBeq8)%<^ zCb8&>8ja_}n2LB)*S;sGOd&zM6+>#e!onlE~5PL+*V0`{6)(9#W}4FZp$qh#%- z2NE#pVtP0IoiA2y4z$E3f27k=1bUJf*;zq*l#iFRbR|0wMU9mxy%ME=BvJYs?@bHL z+)Dy+%mPXlP^AqRBiWhV&5)3UURlKB11@A>YCVHZG+c(jAyy8d?FwN@E&f&I8SzZ?t)@pq?*^ z@2<|jp=n&mJ~~o7ScAh(tXy~u&1)g8B&x4n(AovPXcyE~B-ILtp@NpZX$;wb854(F zli)+pw2R(n&GPQ*{2Q8k`^g{gP1Izfi1UJ?2_N@hUyromY`S=J@#c$olQ$W?aRao? zL75z?NQ2qg-P(|CJEU?qyV#u^65boHZ)ILe5&S%Fns6pE#c9vYZ*&3L-_T4K&1DT+ z*02{@!z{3)aKKi`L0jxGB-lWj_CnhjR*o%#%DeOHpS1bAf8lT1Ox2|tP_I@3)B_^hIARoTjO!;W$G8b&#=FbF;{>sg!sv@p2Ui8T?nsZ*iwiV zU>9KjQ-IajABIw)wOT+Yb;$4yGD@c&16w`h{Co`9yx5IqT|-X!SS5K$G-kCp4X}?N zt6y{rDrjquwDw3pu}6BEVIxMZ-a5331getI_LlmHF+|F&hKK5o9s-v1rn5y+-}v+w zU<;?4gqPDUrscS^g)nld8J3#iWom|2sZ1ikQ3aHp4J+E!rG}`KpmnNQr<$KQ)jU7^qT*Jz37w*Wb{&w$ zxSv+Bd#bf@OfTq<^n!Z9TTvhF(5*O5A^Ri5+I?RK=XnhK)B%S=)=0cY;{Vi0 ztb>_n8_@Q^c`d?Fd+WfxGM6bW#xc>aKM?(zz9aeyur5*lWLQ*04S6ZU7A#BkyHvkF zq56G#Bqo|h(>EBBbx%5SXsHCU`&Upg=dq-t$AG;pk+gFXh1C~pppg=+`uKoCkxJgY$T2g-Ca8EiJvz@R@CIp`}uyr$wV)1 z9%mhJ{P7$18n7(pD_~^>th_2<1uL3FcHrU)nlzzJtWZ?SRxx`!=y=OVa>L(EhF8!e ziu@RUO^q{(`f2N>Cme4DIaYVX>W=t{?ue&nU(4x3Mu8UCLAfQ=EE7D7s_-m=2k^Rg zEM4eMqr{uj=2oMGOZ?H4Pe{05TvbowQo_gS*o1#WmV%8|Bll|LepMqk&S|8h!Zsy9 zdlbk?2^(UPOJUg#xNY9hDfiKNTd5=^BR>XR6H6=P=YjJXHg(4(R9Zr%R|%DPqbR`GC| zrF>Y*ho4YBe8WC2##PY`_Oy6Vr2?&M!q!?9l^&S~EHvK%r``;A@ZzW+v`J{JQc%vT z%l}R$($}H(t+s!mbD{G!=(ILmY$H%F3hG@Tu{ey0dwTs|K6;?UkS{3j4)K4YQ!aKR z6v;h^KO}>Ms^WzWPo&PL&{-7MlXE>eU-aZGQhJ|3u#d5zZ6-9S6*fzq(omZo&21|_c0dJhnlipkS(JNE9Bccb?|CtJSAjbn-$B7Vk}*&bW=E1T$~GChU zYPp%T;^s;pH57zmZlXeR-sb43x2eRsx~!|qtFA7zRni!{;7==P;)JL%VKZ*kTE)}@ zGJ3wCUGV;1_cwh1W>YWt7LohATTKm}CG)(s?&EH?FHciXq%{Dq0r*D-;BQc8HEh=E z23czZb(zq*Y>=F@*SXm|IO;wGCtvi|;z+{zW7JJH#c+?)61DRQ;w;5~sT>wI7dBsj zO)1{%oCD_ApP?iHbrgs64To&4S{@r~A7WG91Iw$ z*o!$AbH0W-vBa1(3|gHCO4Xo-6R>p}+$hSCJYK%w!^C^L@Qp|^SI_*&<0VwFC~kb> zT>G3{;VpM*p>v`073dtJk8RWmwNZf9CJ?m`*xH!so6pjZ`B(hCK_P_~KGx=Yi`UP@endiFLGz3m46{qB$z&~oF*=8j^|m+zG2C}Y7I_jvW3ir z%oib(X3DG^!HjK#y_E@?)efWeeRa#^JWD|;yn+%|P{NCX5_)diP*Rv#H&EH*g-8oDVis)@IOZX6+QsfaHR(NU z^Ln6lDt`>LR22pJf;}5;R?);!M!VU8nCE9)}cr zRxWhM=qVSa_u#(2k*O*C88GBwCdqF`%X5(VjS{7+^(^Tgq>>Ao3!1NiCdWjsvcaCk zzBh)DPs*d?iQilV8K&UJS<_wiviykCvV}Y!Li0wghWngPH4Uen%hvO>IBp=L2D@FHV}G}u@!Y6r-E#EXx`Om z_ks54t?6OTr7B@4)nx88#p(cbF=xf%_gtCt)>Z?>mD+_4rpo(YBaQpRol7N zv4_|+KD?>k4^8R=o5m$Oq2pyb&<_UM@4ZGQJOid@!1T)krd!)K3xfT08gwm$#IaZF zVz21gmVPS4>oGFxusTHwlRi8LZWX0?oD=j^gsngJ9DGA2ktM}+(M}ibZ@6fm&ahRC zb*MXt)3z6Q3gpNFGjT&nq^+(6Y~1vKO80|m{m7gS$8tAjz6!9pF&gM&nhVI?~jU zenm%m8nBBYmO25iF+j%%Xow7GHkL6gTb(Kx+yQ&1HT&;?4P*Y|GSaBDw73kgkMsKe z7>UhFrvY#p0Dr>(_%vYqwpX5P8zANYZEDa567WJjNDKwfZc+74h~GbeJ@7Z|wMm~L zeoK{~!$~B=mq4^uoe40wPMQJZZfrvdK zw%-12c^Cx;(MRfc@_6)nu9m!f7CUk%15yajc~f zP4~*ATA(}~mVvaIFMHzNNo3lcw!yzHYQ&8`tq`WBO8C~keGQd9V^UJ{iOh-2-$3Tm zOj>)5k`4u{eX$y}K$rax+}GIM@I`S}_I(hSQa3)@)9iEZN0!l>6M`w}y3zL;Cxpm6 zlbL5Szj7w?G+?`KEm|zFVJK*>1s%tLj!RUt!0>ZUh`f=RCiH`#aYY382hKeeY3EmR8!8^oZJ1nDco;IU#1HMO&Vz9d` zvAm2gvo1X|5o5~4>%{AS3a`=CZSw(}M1gLDp)(3(A8MAiEOqV$n>V|QSEge#KZkv0 zIvA@FOXYPf5|8ov$KAM^&NG{NX7i#mn_8A+mVkxU1vE^c>uSKUtw`Kr*txWodT&=QFdh8>n$#GVIkKz>cckaCmxz|LwO|G;`_Y&ZJgzL zO9T5KX`(QO@nz6_MgsDhCWdKZ_!Sew50JU?vhi3LWY=YNVTOvf+lw~GuFXkL82{vk z`oQ>S^u8YbhD;6r%)&O#+MjuJornH0GQTfVv|`@8%$t{Axq0~kGMSyaZvtc65L8p3 zx3NO+Juw#90*E#a~8?>m#GYS6^% z#Or?vuST4sjRJNO&>Sn2ONSWJme!JFr89UXe7|V z`#6~Q+nY4g)aT?oC*K!MzT2R^2WErSwSg8l=$;1H_rfG(+~m}ol<;Qvk!d$QuqCiL z*N2d+MkcubxC)v2I637zGC9p=G}(+M`;BO_AG}GIRmZ|xg2v978+Pb>2pN-mq;sd` zL>vbCjG-JPbD}>bCTwZNRvo%31d*! z6*PCVP*H=i^}Yoo^En}x{XvKRU*g6@L)kv$BIb+=G`wt_eeC7?{`?e@oTNEP^F^d- zy=3EExn0yiGZAX*JHvSq+Lr1k{O@w(xXJzHXC9KKcp`l~G>vz+4k=zX&OU=ojmepl zGhfA-J#=im4M=j^%b5~dUlbY}iH;VQr&cUGG9Rs2`f#@ zKldiaUXH?c-QMI0WE#udbIv{IZ|pgLpw8N|CvBoZZqz|Vd2awFh-I^ZLqqtSI{UxN zlfQDN9S0*sSbPQ}kf#a?U3Z%D#6vU0rvx-5pchF%T{uNEfSL=aEGyK4yEkard|6}k z<&@Vz@J5dwnsgL_;HL69%`%cnsa*EZd;*zDMAOSRy?npn<@*6=qNsOV_QL#8ptW`= z+`|x3)mwS=-cBO(fom@g#aUyM&wlPON@G#Ht~&p*Ywr&UX#f9Hot^6Ji_}@!dh@mI zq?s#dM}bDYAbOVf?k)91Bk#QPx&lRGK{2RqU&;l_#rgElO|O-PGnAGz6P1R zdS6EoFwyQczzs6FL$AioNN`zB?M(!4eBWyj?=R8s5>Voo(-dLhDA$*Yv+`ycoXDKW zd<8OtHgAXm)}?{2`$Lnq6-<^=YZA*ii_8ZGy|~d)Zcw1(m$eC+6(L{u(0oRmjhg8s zGo9o`=_Dm%T4IrU+`DF z=8cacOMI;mbly=^H_+dj>@DKxSH z-Iqbj>Vx~K8$aTdIa3k6CNd{7UxQ3n zTq%|U^&FsT3lvg-*fz+wb=8xc8Sg&!JIKU1m}cGFzjCIBqh5GX{S0TC&v)j0XTIp2 z+1!(q{uplv8r^JTvfTNkxft)1F(n%+GQ(>;bn4&Ir8N&2Ax5sC+r&~*<@!pF9~ z`ZqQygDvMeWv)|xW1aFN+LYG04;YvTS~#Hhbpvgd>)J(3Pi4KE-sH}GnBFLEdPJL& z`Uy@WcYky4T}GQvh(PRSeyIF~4GdUtX1Mw>?> zP$0h*(f^M&Nk|-#^QyNd;p36^589MUpZ=if4|s60Og+PxmdG+f=Uqs=E?n{I*g6lI>Gyyz5V z?-r=?1g&JyE(RHvkgJ*Lve{CnY_(=Ly|X^ioB5$lFASwV?l%dII5?9oJK!XIY^?o0 z(-ub7bRA6B!HZl6X{#ACg9#<5vqJV@Ac zUFZjTqQWRxr${?R+82qmed)>^2y1_f*V7eB#(>3=8g9f~ICB}QzpMBm*9vO(Vyy*k#`MR=7u3r@Xb*87Jx{ZHDI3Z{<- zr>XDPCwbu!=i}$*cN=Y@@EmC8K>MnJc3qK)2CU1z+q4YG8XI(x9Li%|&Li{AQP@9H z&`~5wDe;%1u);*v3z2z#pbd$boH;r3MVyJb<>I+Vcr^lL8PEj`ydfd4A2Rbw3E$naF52pR#750PS zYgK3mq&=awDMR0F?_u1F*A_M86guP45~Xf-lsbnTzh1VZ+ z^7{H=r*vV6+~BiPYtKz#e60rYC>wLQSP= z*LCGGf_)6w?*!{*Ig`F-(${Y!eLam=+?0}oU@PpP8!_a-2D~49v3CwVC-pueSgo5L zCG(YYd>M$j(#iQUE$OKxj85aiG%mc#xL_f~)Ch+A{#0EHYOum!>`CF<7}p~6FCFxn z?(vav8>&ef#(vdP^{LTUVs2pO2If~bFi%sd2X;&w83b3|rOIufhMBL9^YJu$8pjIol7VdQJ zN;GbC-+-it%`1wMUuv;A(@0AFvf1|;F}UXJJ7?dQ&Az&#jv?T@F{rNu&0_-Vzk|%9A=f0bJ_Oz{r?>AqDt&za@&}bl&JF6^ zp#H};sEKXOK^su)=6m-Qa3J6v+I1eKXI7}rHf5wKBmIVq^gO|4`9fH*3$36-7s!STWK3jgdnw^ryxu7f{l}qy zATB8(f0l=uXox9Y7)5^`uU@7ze{ANDy(oWdjkOUEgwbu=7c%{yU1|*+%{P?3oJQvT zOkKIz!CO^I^)r9WghNvOx@^E_nAFfGGAA-$gv{P3EkgiP2531!Ez$r(rRoCvtYAUpiAqpUzoun zZ787+^|LCHJ<8dY10TMkN`AJ7s;O(K+f^#kGed4>OuSCK{90`f54;V=UNypD zDbC#{*r2W3faZNk&jlke8F?KF!`S7`B!AtjSmgHZ1`0#l0@}- zrCu~EfM*5pZ&d(4&7{jTOj+`uElHK#z_q4T74o|OK^N$C&Xq}h1o%{Qp-`|;>d zsJ%s)X%QFNBJiA!TQ|FpOuz9_Aw^Y&ej;yj@2SF^)J;Eq>-e2-7#9oL(a^9&$z^yN)wtBnlFOpYCLEZ zfeG%{XcCYMF0i$>c&l1TPYAhsLwrZxUr94>W=Eu%NFPbNCZR!y`cl%|&-5lTCo*4y z%)PQ9YjY4T-RmS)XbU3rF}AjCzG^@5(0oIt-S1b^8y>7!q?qti$Q5*z40&m%cOuRe z%UrR%XvNYyFQ(mL6I?-&8syk}nigC}p^t4lQ754{q<7%`4Vfy3lC8UbX+A7Zw@A;+ zII|ufnANv&Hq>jLvCK1;SDmr2XhTy6i~Rt!HiEvoL6=xJTbihy(16~c`M{SThhDyr za{b7mCp1ZqO3bUU`IAEL@8B$=ngZ<`n~rErRGDXok3iNLF0sLij-_(H{+Ix?3YAG$%A)15GL^ zp=hvL3{Xwq<4g<|m$nF#o1M7KeuJjoH3-S^WwuD6eY`e}NHiJcvWeCnFHgR&HO1L# zB6A}1HOTDQl~ot$y(uX7fW#g!tYu42LOi!S(VN~q98-KBc)uZ&gXqHwq?s7u;dU7^ zA6xgnA#-o|uem#!yOS5~PD&(=ia=s-YSDE!1+5GgTVK}XG0w?AyBp}f4D>&*(7%xx z%8nn^`GktOyKF12B2B`_c_xJ4MA}T#8M8TKHh(2%^9Q_X3y1I;V5=nPvOhL)bqG(^ z!Ob{M^eE|#;{5{UujtHo755u&7UyRziwUcRb6ghC_e7v(Q0j~tno&c)5jFG!WGefh zmIdW|3fSHl+AtlKCAMYl9nnusw5E5D$84Wy^ls7 zCvU!pHz}edHixhXP-+f+mxH{yYYXCvQ@#V!_u|iE-n5(kFE8O6I#V+~-kXF{#=PHm zUPYXQk7e3Fr`jN?snbrK_C-2vU$*SE6>OdZlvagiy}^>Hs>G{rCmL7Y?09-7cG_-A z$8XNW_;dyB)&qBCzHYtwEO(+zt#)d)FVbq)Nb(vDuvP=LZ4dd14ch8svB5F;L=FC1 z9tquPU9p?yVN+Q|d8%40n3DO}%#NwJ*|Zml17u%t7FORK2$&6-I** z$QA1v(NBaR`~;o!zH0e4*-ANod3Tbln{)Yf=zP58{ByEpe~VI?d(OG%e8rxVq^~?$ zgQYhEZJ|)U?yU`pM7&b2XVIy5T6t~vyW0VG(*Dr&k0UWgVsunSzbd4J@v&sf-{2`8 z`c^(V;W^>?3V4dyx;6|Ld$+yTQjp6~XwosF%KLK4AoKv$Kq|i&o_u&H7Md0x-aSIe zep|ie*IvjLOwz<38Jd{tdw@kq0!zysg1_TKu)Hi*zw z*WS`ju2lTNN@WixIj|$JCi`ckm#9ckSUFvmj;W7t#zg-OPiHfmqwO4RUp3mAv{g2C z7-b#yt`f+xx9u+LhP9O?pK{q+yxR@_MxGY$OP7DcQ`fnH^Sh7F zjA#<)B+lO;&ZncMotN0657{PU=Oy)b3)NWyylG$qidNz+0?{THAV5V zVzMVL$%1m?b>j6uh1YdU-MTB(#s#W0AXOByxsA3aQ#+NHVDaE_y8Gl0_AaJr`FWJ> zMi#1hS&`rmju(b=ddSBMHYAvp()hB8`0)$&drT2mR852ZG}!-!!T#xqcsR=2 zLRGgt@~?7*T)aamwPo!pww~MIJOpgLm*syWSVR1jh}~>|Kfbl&UjtZwOt9YpOU6nQ zuoJNVDZp|q+;mxBrFiSzPADA-=44e(CGy;zOuYLY{t8$=)QDr3m_D)@b{AnV#hX{? zD!bC-tLZf$(wsz2M6=*sZaN1U; zO4E}9Q$7}i&Hu!!vIu=N6`HXi8rfy<)h7gDFQ27LvvlcKN|&C->mqyW(bB-Tz3*k| z28rteojq7EhjhIfuSd^S#XWEI1Fz~7X~B9KUZ3DsE}NF7X=(aTS(-?e77_^~#sa$b z4H||+XEV+vv*?^2oHw~IFX7D&^x$yC{NPtY)=Wd<3xjzdBlb^uNt|YT+H6mIReRdH zwY}IdVU;yNa}4M!8Vnv8>yFKFE?_Wka{u0jZ*ml2R!E;^z=R$ts!SJ#Bt5P+`~#iE z|I{r`&*AhOUhX;kftI96wDz?FOVYlY=};RsSU4P)CWUfNOR5{)y(HhS;f{8xxI^K8 z=rj|ovW)BO`{&=LA%fGaG|fu?DYFuqkY0|^fGx?UM^E4$* zQ__FRl(hL6ZQT&I906LH&^KOS6Kd3}5bMMe<{!M?&GX&c5f2`wD&qCQre;=AMi=Hl zoX6|lI6fCJa{==k3z+Ap-xx6>7O0GM?|s^{eQg2P#+xRhEp!U6^aE4Uf$Nt=BR-a< zyr=uB@nO%fJR>CW4>HjHjaMy=oLA-Zs{B87RUVsRAGX&fdV(eoNVWi4opxuCEP5ih z@O!|TLo7FP2B^0gB+G8r2Ui`A+mD^C3d9_Pf-}z!{G%4&T=@Qi?P^zSHCT8y?>uK(m%% z(QH6hT|i^s$OI2y*Anqn7*9cy@x3AOuh8VfL08GdJ_cQ5-&-_DFH?Dcu$K8QB$3v7NzjyloTO6{g z@c17x!(Gi7&8|XbJQj!k7-tjB=Sy?GG+*@6j8zxjYK6Wn8)#32j$t50EIqfe)VXoC z9vy$@`{MN9&{Wd;a{T>PiB?JY|B*DmkFz4PGI3TWzN|8Fkwj(Q_O5;dUAaTWW`Kjp zWF2bZXOJoQp2PcB(ySXFAaf5+u@7X%?#fMfxon($hBSkCR)Nnd@K;rVuZbg9c4)ds zd@i_$9kmTc8nvj}mOQmQQF{+qxC2c+(10u`^J94u7<*Aahg=3tJ`GLwjCp`I571t9 zfVR0W=AB?OLC~NDdUJ--O`7#p=-fQ3d83EWJn{`;R(_m^YKf_%$7N4V!-vrPHqT~? z;}n6W2=pQm2)C6-H-@bZ1GQ4n-l1Uf#6RDkcGkw3yK1QbB#14^}!u++yl#wev zu6t@e7puTVG|@TH`66^~78u$RqE`bgLufSyNT_amW>Jh&ugx8ucV3%*BR=eLO5Ek) z|Dm%~P=n3&D&DLgxPj;!Ha#hAS`Mb=;6;{${D16SOL8MQjJ?aO2N3}A*KNoodH*9! zq}#2kwpEf+ks8;6J1=tSCx8#{gNjoyVdGgq(i7^C3PB@@H`O{0)boE#&U@Y!yOeU% z2^xjsm$r5vnwn=mHwhmvwco($s>zEBT3pZ%aY3_*A(F#HX&}=LYVw3>)n>EWnGOlx zAA*zkrc^J`qg>b8RQ3`{cv>7$KJHWdj!j&ZrK_^^O_iljoKWUun*|%7i~uQZgQ}Vk zW;&AQUWs%RoA;Mmz8OVt!v4!d=6mtBCC6zm&L_GK^9wZD7^SSSxyI(tjLo_g!%Zvj z*!|dTCRE35e{{+=NNS8j{!X4mgz0)(xZe|T3EwJ5 z!#G#&=E~iCNABj!fNf>(=}v_~%|JLAYS{yG-Ln^N9&sp*Q~gr>0bp-d7+MLvvcHx> zh1JfhiLl3j{jv~KAxc@cvt>JbhwbcTz*?Up_PWv8bdTfQ2x2q=>pt0IGcU*FfsX(y zdGlN&n)<5~ZKq*Pi`h@UV8s|0UKd{fD!itRVq0ezO(qDB36UdU<`%O$^Bl(xI8O{% zydfEsg2k=}9OW!3&dC3dc>S7%qPwDa;dSBlZ^EnUY{-iHe61j^0byG}%POOn(uoh0 zy?iiE_sS#ekG*Mo<^I)Cs$x_$u$;CKKM{BR6|d&845iCZ`W8d!%XpoGN8j28Jp5xH zo=|6Fpx&9L;B4dAJ{%XkD_p(xucbw!Ma_sdkW!_Tq@WhN*O$ts-|irumHv-<2*2UgQR~q|P69?|+aP zXdH-nVx!^lYz7g^6$7|p0Dme5aCRz|OweoH9pFLGG!Y7wCaxt$Kc@MOPlNX#hi3VV zJo+y*jj-VLtm;V4Zp40?9RG3I=vO&@(PFD4VwFU^r6l5sscAK}v?kDWKget`A*cjw z*p$j}8-6IEbBE@gI*1Rx=vJz=Dtcb|U5~wGKRr(4cVD`oQsK4Gu7&m;3+>Af(4ju2 zmk!nUG!^U!Y1}|<8rmq@$FVgxFLd_-Dt!Bb>MnM*wy7Ft5iEHYU|;A*Gb`%>x*ni! zd4Rr*SF63$CKYsgf^3^YGga6-n3%%)&|?zd`w`e51NLUlE=vAtbWs&06p`}|GLP~4 zmEd)hTyC1>rg?{(=4HG}YkidLP}3QNTZ7=HFw2l$qD<=gJYMaB|F*dN39sxIydfzx z#-!^)9K<_d@w^!5u4W#r588ty0w>m~PjRT|9 zE@&6J(UnY5n}Gj?CLx+&7CjG}Pg%#m7VUe8FFn%IBfUkB^aPW%7dLRufL>&P z3>~mfEr`}|GP-j;gigW-mr<6B-m;DtE^$R?atTT@rL!_u^6{ek4Vz|(3!4j@KZVV{ zYj}+&`1U~>RfpJShr*kL$&Sqfs)Y}1KA4>O`N4m&$q~QRiYjxcN<=yB5&A+y8Y!-w zcI~w9*lAyWga%sK3vXdR4uWJTR0@YNvQp>Z@B`U`A9yW~t}-QV;5DuARm-3fOzZ{a z2T3E-Ld%D`e5ikw54E)!?wdfi*+8@fG$R9@vt;cXnj8q~{lF{VDW9;5_-EVNm)+O) zSciY{N?0gEIP^5}(TlN3Zn%ivMfARd=zZd4DoCs)I*=2CY)lZ+J7{sqveiK{4xy7C zyi7H2PE%K5x=vF3Rk z&T_y3^MOu!xa;0f)H^51Z|KxgJ_;!EJaj(R)PG}+V((pCvvbYPADW#78;3@N>A8W_ zObE^mdLip1NG%SXLw7sN-N-@BoBlK}oPL$=W)iY_q0{PN2p?;Azk$} zh}jd1Er-=&xp^hd?}z!*=-l78zdbuighdU@dFXun?EI=$ z2#WN@>@H^a9n9_%;A~OGoLGT!?!v#}yB{r~Z$q$*SyPVPT#Ri}@B zrB6TFu3fMq=dHEzc&q&y)~f|+5kiX)`YA%lcJ=Eh1;$o82o;CAr`$(P8?pz@v47^7BlQ1LyPpHB-Vhfl7nQ3c%{|jx(M}T=c{~K{Hw&qmF)qL^!2V5u z9i^wK2b5_W2sek=+Yu$$+9q3~9!SmpC_j9V5%`D9F)oSM%rT>aCZ2TK%hVn(zh5UT zp?O&$fh#2N9U*~FkVZ4+BySx^7(p5fw44LBsD%gn-1ykbR4(Oyh*8`mja*9bb(Rtm zo2U?f*! zvvkl-r3z-PM^aFB-}XiCPtLfV0BCCb%N)96RowVA=XO4h8T$%N=ge3f(c*~S!4W;N z)NX>4H>n__?tv$>LoMt;v-jZ{MfBLcW!DkigC_gu2Vdrgn0bL zxl8t!!fz@3eoWzKbB4@-DJU2Wfzh%Af{d$P})aU*eoMt3=700I+ zL>DGu* z*(#qQxPJtvU+C5y<>PYl8#p~9)G*Ei=PP88S*|*WRR{4ybr4xcqlOJqqJjuBG}i&h z>5WF|)eb4+RWE$Uw&ME-a_fvzG=EP^px{i*aw1dv_{jNfa^l|fzreY``7_|`V;GlV zu=VaBb=St1QDH;cq#LFp9t5Y{p@a4ulbfD0bLaB=_5BKmel1bTb{C?@{}d@ zjVK*rPy;EmLG-crDslH{y*J+ufzv*NO8y8=`Ao0=GC3(e3dQ~bXC{#aXE|}JeTA!) zq*b853iRJnp#Q|=WGrlG4b*3Vq*urk1#25wOJceS z^&{Q=3QjjP3E}fb=Sys@t>&cFob;CFq$eh)m=x@hkXjNXdq57YkXs~Sn{54%A!Q$o zcLMr+m+r}pfIfCl@oPM_qWE6W$!9sp^f5HQ#@$M!Eyw3_eEwCAPmzvg^9F)dKz!_R z@;3IrI8B&qKep-mh3=m|^JdipM-;mbQ-N4e3FqyVvc_%wK?{m6-(Hr1&LX6+Sh!k}XBr1F! zsrw2zOW_611I9=Hj%=L=9-f@{!I>AnRh*elbw+=jehdnI}T2ut?Rl>50A5mvfk3+4$Mu+iUqq?4|>#6#Vr|QdqZJSdt z67+$4D>nv&D1sA7X~wnCF(b?q1NN5gfsHADJFRlb;zdpi=X`0v;%X9IO`?BSlc<&2 zhqVUEdz0wK4lQPZ5{0(xlWRX2uYWkLYN21=7-eB*M)uS2`q&xs6|ehgcP+$gA^xit z;u(@#v;kx8&(_?d8k!r_5!joG4LKBSv>#{gpH^?Djw$(X!A73KdnjPRv*xQm4rurm zejO^hB)?1Y`wq$P%L}p79A41Da8{6N8?-hJQi>FH?{z!WnWk~UhuWnZjFX~&@WKBA zHeAxR$XN^V6M+5pf(>6X;3Wfoj|})_z}m-4wG(Vr6l9wY)k_5}QprcuEsu!}p8zc0 zh;k@~q}PpD7@2op&1ry@#~ZQy7qD)HVx3^u3HGl#!FCgA#uGw9KteWXOci?MwzZ5h z=$J<}?&b;pQ8KZgdh>dM{YV!qgPx$P2IwuzwX`qu5^VU@&PKh><|+ za|53`w^lkw9tP}v-)erAQhWhyu;f+E?_LB2CHSlX>yI@P-vG;ECD%s0HsZf&BOZpi z8`U66v%Oh(LYsX6Td%{llFFf^`zxjNN5JmkgWoq|b5;MXBu4knZwi(3Vjv!$VZY@k zg%n+9*mZ_|#~JpC1C9nt+bY4B13|12)IMo9$e}a$R<~o%)x7Y1MN?kn7C4KcT@S8= zC}J93PE3KIhv58L{O!Ic?k{jIaQ+N9v(5}H8|aJ#@iL$mYtSMkOXHq$jQo8F&hqJO z{Q^$SLf2~zA(ObOiJu3~$FI|Gld~wUd(FDnyyaf=%;Y5P(>Y-iC6KBP88Kj#Y-N;6 zTONyOd17+j?1<3}|IG-;WEzH4&YPUCfRhc^OLVj5c+R^l9ZxIMnCIPRVQ4Nb4|`4nw*1ps!4~E z&LA!gYWKOHTr{(B5X!0G+~1rxz$v1nS3<~3qEaa*Ht?5+bMq^MTQoz~QoEMgcPzCp zGq~8ZsxGntZDd4 z5$#u6U5oBobbn~k4P)w43lwDiC*Z6(7qDzpI|*kTh-3MHCg0B@^qaL#W`c5^rG%mw zrjmFTHec%aHZQcM>6)hRn5Iv>LJ5a@*#xTl9>?MiXP=8xQIGAK?#IR~PkFX9GzjKfUmV z6$>_xCrfX*E#LjgoQ`O^M2LQ{5q zp^}lVMsCk!h)K^Y5%&A6`7?Qe8A)(Kb3yYx&?Ks@Bnj{_Uz_9!%FGK?Z$aB^EcF9@ zPIgIguWy1sJ>5T8Qx)^~H7!bZK6RwMf8hK>W}Dn;-B8vIT zX$;P&47oD`XGVySnTegW`-o0>Xr|5iGu-cQGcDV$6-be`Z3)1Ho{>!AC`D0D`3$H51NO_-0pE`KzVZ7#9>$a$L zQR%y=w5tqqbr@XIujNoltl-6JmMlzsz=LfUkqg~8s`w@EJIMr1($@pj97BZm^AYG7 zXg(EZP3G&UvW_ZmI;x0t=3XmgsSccJKuw9kvJ9a}$bJ}_H+Dllv72_QNR{l1HHDZB zInGN*c%sS0vM-U)5(&LaB$UyH`(|J<6RM*lREdDvrMFEi#1BM%eUK*KxTyGr_C-R( z8u?mch?pe1*lF|ZQ=KiQc_DKl^F7E6X|OL`o04BL z?^;rrNUwQcmXc_8!gLlg?Y<-B&tL>(Sa3&{|biIEHXHsS6)9#R*=^b0IbN zbQ-_feG}*(PgNsXW|n1Ud5M|jX~1rx%~1qwGX?I|p~{TM&0exL*X>B7*<*m+9ffPFw<^n+k?*1Ym?S03&^mWR7ZO;o)CZ>0jK6cD*F)KW8sjjH45M0}rN z_Y{FnO4ntuP~t>_b{fOpf5HB|)6CLRT8hA>2z-Si@M*wmlAL;~P#Y?+M25Qc2Ca0& z*vN{>LBQfo$-_*X-w`7Ts`@o?-c5s)D4#YGKcf>giKP=A@y1fK`2w`k@K8YTiB zZA?>X0Z*G1Cn-{oj>LFVb1$)f)A7*wQbGu8B4)KX>ka$VjyNS*6Y-je|D}moz2=7A zAju5Vonb0Lq|kHrx)n>E4y82Al=<5P>$^gH&PnmQBbFRf?MvtFh@Ze~B3f$SrS^S= z+V^R^CP$yIR50uv*jvon2!he9dWo$#9!l|?c)j<6-5rQ?;%jY$Ic7~3d>URK*b)En zg0;x&sI!hb|JG3_w_I^+GyG^6aQ6a%DS=luB;A8{hrY+ zE@`J6jf_ISf<1*2qE_sk-Z|a-xQIJ-kd@^Lc90B%z9BP`q~v&7RT@^6%WYp{a!Qo$4PXTGo917cP526rO_HiO!_ORs$tJFpk}h1YwMqdnUUS?D*L zn%!{`@cIBUQ!7Jya|o6SjCDXzZ=m6&B_(Y~`qZXS;X=2!MRwsG zWQs9g#k&?7#)0XyZIR!PG5cviWto zBtDHapBZP9%32Jq#n77;L$wP^X$@Sbi^aQvCr!{XXG}31(@|vJE;*bv`+KFNIkS9? zvqFp*85K`M<}+#qT!9NKaN#9^3lBUri%6j&2#VT(LmL#X1}TlnnKh&wTLIle=Cp?H zI6pa=rf-~?)sueI#JmleY(i^gyH>WZSlK>+%#<2#Qwu-DH{gN+-dlt2-Aa?nT@R#+ z`6bbvR58{|+T+X=f!`DerY`v-R^cRMJ~7Q&UZE!|^yDR>Cl4UgT~jZ_Fd7zMMFB5u z#)lQbHdEX6*anC`!w_z8=3aallUrO>@gEOO#~lAhPxg;^lTZvFrKZwtZQASlCzAwJ_(o7NYZp z+$WAH9K4XZkohKLddE?tRv;<_Tr7c4gBj)#!NYR(qsWw-&riv_nVU%V&9H)QDN7{Z zBTagSH1R%Z(tnXD$%%Cd5S9Sp1pf2XHR~JaGo|R{B=E)a{tTjP5LQ z8TWhCW+v{{U`CkH2~AF8(kIqMqPBWUS5N6HdP*OeaW@JsQK9vbfJFyHiw+cAdDtdN z5A?arr{yKzR>l8LS@`cFmz?-o4Kt$3D{CH;Kl>0 zmk!xBW@M_d9rLT)MW$YOM`cSP$-hbYbRIuF&g0ByqES96&c*MfC-O;DkY6$_G`VBo`6sgm_(sa9(=JH<9Mhu0gdx9ks!f)Ik*~&@@^LYhCjp(#-jD#dC`^_vTp( z)2jl3Xy(G7=(K*~Zel6%+5xQ{(3^HZhAuU-&g6p`^wp+mj0Cz!Q*jySaR`}wk=u4o z-xa`4^z+ph}@M!RYakU7oD`}2@_d^;=oW1L>vprs8uT^sbk3J7}&+%SXIp}rC<(4 zhf<>gi#ZhCD)cau z=6Ywo>77|fv{K)|XmX~vfGWAeh9zYSYsSYmKykr)SCh1p94(^Ru9j-eq?kON#+l}K zk@>TPflO`X)2@8lcjeRCHmq%AP^(tpunN(6fc2CSb@pZ+B27#ezP$oUm$at>3bt=0 z420qqu5Y!QV63LG)im~!rm;tsvy{CD5oE6h%qkF@F(gho^;xM)hwLVZcj^{IF0_*y zL>7s@NK?oWInjv+%_mks=Id;-&L;0Vn{?qCoCT81hbBsc8WW!0%tb8*A4wvboEB%@!80efVwNmSX`g~NvPg8 zw%ImncP59vjSNyt2dAw;9m-fc52r&1O}2~P-)8e}+$CrCPr})h+&xk{Pik;n1Y~IJ zYi6#Q`I?!Ta26XFLr!S}$Rk=2$`xEy2H)JWPoT#o~MLKml!DWO=X98%7zUecXp%ed&T zfW4cui5lB=oh5cd&iTCZFn$Ql+p`JhH@C|gnrmpjWN2E)x1tlmNdckGTP7t4O5ReE zz~)Dhd4Fj7h4#o`c);>B&`oG2*_k0Ehafj4O(;) z@z_!va%fJC&z*;6d{wx~ik}afNa!}%;nQa3<8}6SW+E!eLgqr|YmlkMwx)%lMM4lv z16;OQxH)o7$#b%!GxI(&g?7&-#;WnL%@Q&)8(Q+Sph@^xI(r+_<%(}(dx3L-^A+IS zlt*mYq2?`vpbqd60iG}?vQe!c2IrkHp!h05kBvXK;U>lT*rYh^sriISQ++M8YoUGB zLR&I*Ma~eKJBX4($)V7`-}lXW_I(dmTMdWo_@GZv7R5>%@Jk+<6Nwprbd4Nbeyovilws;HVR8C^3+BstBN z?DP29<5sXKxL9w^_11jRTQexs1|o<}E11uAO>PNHdpA#|4L@WBo5;M+&)U20{f3{- zzacZJWoA0j3iix8%f67gkoh8Hrq)NGY~X5RvOv>tf)(6!@Mfcm9FpjLyd%FvX6%b+ z)zGe;VC>0E?ZgDV<1;g-xBB`;0WAvX6%-KmD7|?DOsXK93`!S-foTiVoVy%q9@6}1 zX3D$n{r0BmZ{2vmC?FKEY@V3h0GTrvsjy#O9S(&^KfV!>RQ=2%>caX+yzX3s6yI%|z6XuDSOLHs2tNJ8N!M z7yVdsi4@(Y2!c+7EIlTN2!G#n6JmlPC1OE3j{tr=W94_iM&`d@zFxBH zC42Tu_8V_jPusR>3b4%)Wa9v58W4k89;918mTdbFnfj}m{$`lY&Xf?c==P(s15XK3_2eraHxSbAJ-H9T~6e!mxE1`=j z64_~xB|N_W3SwUN?PcHo3H$cb`)?V|TS*0-m)&$=1zOiXZgAQ`I+kF?c44_ONyffWj=&BeGtp~27xmk_U3 z(=jz+zUZU-tL{Kng#|yRY=}ri+JCY>wHL?ZQ_ih9W-7LHy;;|r^(Wq}PXo4%lACCT zoSbH)QJR8@0VdSNY|y6X0#-U_%-;tS+XUP07XtJ>4 ztZ7MmQgYD5J^AX*fVN(d#m05&8!eDS_A!@SYkp zHXPOvBOPjRnUK9ZQ8is?&*~=P`5N57NjwJ|o~CqoOdI`Sbqig=4J)|eRlyC?1v$40 z9Fjoh#k62#2$XKVjgix_w4=D-{a0x0?z$`#@^OQCdl@TbIj{BXI5L&UR)_EE@O@E- zZ|c#zasu)>GjmfYi3nVZdGtnwkC{*(A#*afJ2R8aDClF)O+G6L=dHuedWEKVyyvEy zMOPChmqijSlITSw(Pmp0EFC!VtZ_kvLYo6_Dflk0zd4ry=w4%)CYBEd5?Gp(PV~kxa;{jM5Y# z&8AT4KDD>qU|4O~xiWV6kCz@b zg?+`1t+=tDh#UI`G8+vabA7EikD5JY@KPK~<3U|iEg!Ia&Y-^s(ptrR(K~yJPYh7j zS$!X;RT4g9M=`U7%!SMsA+rxr_dsdsD7#4ogWHW9(=I;%4ykCN(X>+BP?XH1FL z*<_tfUUW7=Mn{>cw>%%383kOc0c|#7VBI#yL&*F_9v|(UO_W8i2hHR*`}nh-hRi2s zCeu2bth33h&L*2`H>@2z&5ms!1!~?pWStrE?%XULLZ)BzJ~H#W!TJW7mLjg(Ea_W` zZ=5HbeVmhdJ2T12*EYMh*%xiIl5|V8&wivp5MqHE7GTCT5=j&~;L?2S=uKZs4HACo zpU#Q=Q&nhWn-$yV&CJIP&@D1^Mqg)>bvAj?*`)TNh~1%cYam-MPc!_CahW`2EVie{a~^XD-@PuRd%m(*ZM4PGWSVB{_34N|p!mm+C|X5 zf}m|CS*v9*no1zuGI+xQ6xqnr*0ym-Z=iaiuQT5NT4^!=2~SCE@)6c$vv(Ac&(rAH z2Ew zL36$~HJhB6qxZyXQ+y$FA@fzp+_vUwZqRa`373>-m#4#42y2hZg%2cL&T8FD`dXwn zk%<@HL1w~0w2!ID2~AlNA)l5Ro$^E13DfU8t-1y3N*-CsBQHuGQBfm7hZ0#ptYoMo z3T%aQ7B-hSMh59Ub^BlN#2s~eMkD?>Z4wI4%xE{;LFZF!5aDBV-nL`AyDzQY((1iR zt0x1cPDN1h8QA5D(+{>mZ3&~PbKoHr?F8r75eJhG`l1IrqwyydEgSkQj(_D=tCn~n zb0PCJ$Skd=DwHAjVj#I@C|eR}mU<~(bD~30daC!ddUI^jCGE9`Wfr|&Hw95OXOq*A z`NR!Ham~y%Gha0`$r}=5hc*&|6ep-`2->o1C*GnTTWIZ`kvidpbsw4LZdYV7W{;Uj z`^uRaMk{`H#m~Mdes*jawh;o&JUt1nP%#@!fq9Y~qv0_oC|~%#?jSB{FR&{|=*MwW z#dG$YcLTegYA1S%qYYd7_N8zC34Qz14Y^!ft|=-w*6HC)2Cm6L#c8ChTjYEYuXh6W z=8ijUoPXkVHdv>Rn@Y~)Np0U={S;pFV`AtJd$lpqT5{Kt`x8s<(|}D{NIlQCqB_&P zgrGVW$jV+3H{Ime>YLx|{k|Nq@{Z`=2drk!^s)M8_sG+xavGKE^boMO?SI1Z=95`` z(c+6egC zp*Rb#IS!9f4o|dBFYEO36Q`G_0ZZuKks8z#0wNv|lpCl@(xh9_T22S-o~gxCva0}a z3XFvD#MZGV4l*c<_Fc5^t7zXIJtK~Qyp1UUEFB!T03HpyRq90#(@6JUrTM};Mo>W$ zzlJB++i%Qz+Uon5M!H#j2{A`r+T5kh{RwUE)1wr()V3`rC~v&)n8hkV9dO7dwbsFY z`df8xlxi}(N&+X1G^@Dfw72RLyRTqEUuxZ@*8K^!?$dxBl6x!8u+dgQtW|Ke4pJD4 zFcahXfZaW;a>7r$FHOg&dz=N>C*p}Ltr*-DgZncvxKHCXq*IU&s4Wi=LWL@+0FB(G zwLFF%^N~Ixmn7ax2XF8?s~)a+WtGV`(Rt#*Cxj3=Y~gj`^(XN94Oy>d=012LGZBcg zLYNBVG}4qW^{R(2sQHoPVF#JQlh68vOv@O?9>iy@zII&lK%PCX)S{JI^b@H?PmfZ| zGPuMB8%G9-tw2;`2rT3rNva-7=KKy|c_;r*oH#zrrCE5sU0qHim-6G)_YaK{Wz;1q zT%y8%l&BD;4-R2qLT}7 zmZorN3ja}>Ldo9HEnpOHAlw;35(5vT=%Xh0qZ{!9e|TJEFUE6<4nDnA-7H&5dfHp{ ziM#5w4J^Day#4@QzwuV}&AQAQ-`;WqAsJAL6v#-eAd_%ADpAt=X=JuPNrOHmH>e~e z_iTI`i}VCCQ_y0O7K`*E7KzDa8#w@x5hTr)ZDNJmsJPDN>v5=JX(IEHaYlDyJUP_m z+U2Xp2}9z%d(0EaR9<0ZD~#+%!pNQ`ktlifN(B(jK#DndNCs(RD>>1qbo3tc5U;y| z*nue55(!PrgdC>{9-g_!82R73(1f9Y{g>vhgSs9Pd8cL(Xyw-Z$Xt=48KYUyCKgx~0yUU3ic z;O=q<*prEB1n0{--xD*Wglm7g_NSlPpZd_;JtZjJw==g^pjc5DSz2%1HQKRt%u{9h zuGg0xO@08&GOMEdbPA@^ zSiyU)Fl!3TI7Hg9OVbzhx(nrXak}eOIg{g+D2Fq97ng-{SSW}86w0AH`AAGKs!b3g z0k74eMadSDV)C(V%rm`;?qbZ?v(bH8BrGHh9*Jb#pF2k|N?70b0 z6$kO85attthi~*;!Ey`;`p=omUn{BJa3@bqRps9KT2`@*)O(q?=oDln^BUx?LGGsp zxs^6X%y9gD`k@6V9&8^fUNlqd^dHpxAs%uH*? zvUV(=+OedBxz^Hwup0>C0JqkF24@+ZYdUZx`ie5eZ@TCEGr{ytG*V$p6ol6~a!+hO zlltPLEI!IR_$V*b%o3bK#Gpxhb+Z#nCWfArux9r(Ugu)}Ql`oyWvbtBr)C=FxRVty zWm9v`5m!kQ)ARl3pUL~d$=3<@I^q7*3HNlbtRuFk<^V}$LdBG!&170Ud9&BIESos- zS@xmr<~3O&!|$giCgzkWn_N~mF+DGwe~NP>0owBAE?@3De7P@FP99C8_5nHd3KAV5 zR2&M{p;nXzz3!Ob#2GhyJO_%K?o>`THoC7sB}Gn@(kFXb52rP^U31%a%xzy#rUt2K z9Ux;fC)lhI2^DNcMQypH{JL$3(hc#(kNLU2Pd@P^`G+!zk&*P1$_!Ll_}qoheFr}G z1!a=67BPWNh#>3&Wt0jb$%CSKqIpP}`I$1~hI;{|Zuy=Ktc=c_QSmZmo|w>X;LWAX zrOeML(@RA3+96tGkdO>z)&{|?No5P;*V9|JnrXkoSsrz>JGLR-`0hU^wA<>0^t!F) ziJF-+t=-AmoqT9_LW&_Y14^<4(l)q!^nm8MiPt9MfZt$Krr+qX2|n*%W(Ozx;WtQG zEV<@S*36V;jc3<*_Cw>@iq^Bp1l#=YGB6;R8Ei~+NhzWqtC@bI$K5R7aIa>%qu;Hz zWW4QkI9*mVPcRb{W7W)6Ge1-_g|P^0f@(ascV>f@!3Lf$s0JK0$ zzYso4Ua=eRzBAS0&WmRgQ`Wd{HhW?MB#GB-cFkr#G@Gq9tuZQa2?dEZp`?s35?X1L zOO-?2tjfbA2i$(xeP^0Rx_7gjQ#R3$QZsYTzLdF?`5|Re?N}5Cl$HdB0T2o7-`yplO!>ek%Nxr4sTdb22o2;wGil#aO$&CJ7j9#l==9bx$n+X+)hsZQRdfyq@$=@RWt25pyXe?Jxi9? zLvuYeKlIRy%xXy|XwD3>QG_aag<89AZcdLP=q&b=3WxPG3 zr^eYobL?ru<}PV2X?{qWDTmZ%9lUS-Y?lhPbORe?RDH_Pm!|#>xc+O^w0-An)|`Iq zO@cU3>60%_OR|zvR&vUxl2eE!tayh|RuF6nsyKoR)tPIntgmMp{VJM|_a+j*Ly!LK zXEWU)wU#O6gkNc2AM9sY(=zBSgWiV>dQrOa7G=~L`S#SD;6nwljAD|jRzGwI_EegG z2?E@R(e`a>HxD#1xz23h&(V5+J~bspvc>9Jtga8Sx<*VKJR1x&0YO5jIs_P7vgox) zJtockn-Bfhel~Vf7uX{GK)VZtVRF7qnrAjA8$x<1b1CyP$_&aj8+K?~3P>#uj?JJY zAEl+p84ul?Z098LuxO@zw7aqV$mrz2gd%cTKYK=*+44#jTghVYNEUl#r#U9YNCYj~ z0I3>K9Rq4Fi83M&IX0fP8$DL0{~i+k?@LpX8GX02nu8c+-#aU(cA9onnYfLJX^m&s zc=jFR+0&?KMs3Q{Ah%jUX0~nB$v|c!XmVvd*5p1Dtk{iq1k09l`~cF11xeQy^eXd|}#BFa!B1m>7Xvvkv-OO?6d4t9)tN;&L1bitgALn7lCrVU#FP3 zh@eEes`s_$x7Po%CWLuj=%9rTdIvh_eD6!Wn0kYeQr{|U+YUVg>KvkmQX;>eL-wop zePZ*Ao9?Vdg@W>Th0WQ8StQ9-kJbDfDDOt5eUe^XT07T<^P~6uy;dEXYbZT{m5No{s&m$Le-NzILcgnD$rzj)!1U-)oGQC1L3a}b_LFrPi?R`1lc#nOemhJAY$7~@E& zSL^$Z*7t={s-3!1MIfra1v)gSUlw~yV~$d+OFb7#J+ls;df z{_9nWq-%$|cBpUJp`I?K+9k+6Kvf;YvVu$Mz_U>;K{oO+jF>%)$Nsgb*?X1xuk5~m zjJ;o-=huPEHG)0yDizClAyF0*c-6FkYN4y8s?yNNfLh94t^I{O^%5?T{reUp48%7nD^4_((4=a`odckv3M{}7+4jg za)+3RFy@fl67}fEJW9`$$@=@W=8x7lG{ui}vy@OGa=uKNCtBYyUsK;T^?k?G_XTAR z9b}Vj?3Y3lkXh?&#_e95Lw(&c?>}XVrCztPI z7!?-hBp8+Ijbqn*3TbLIfnmtCFxm0Lr3=kUxo~S@>9Y@gI((ex{^Xc|; zH$-V01>f6QF=oNA%Zlci;jD08z_A4!`w(zUQjtPZ!D?oZJ{d|M6{y!yg31UzhBb>4!7}iOlNK_Ew3WcnJ)wID& ze3%`(Zh1woJA)x2dVQ|f=R01Xr)>!%b4w`^ zuu%p$=et$YJL`x%vu9Jgtn)oF$hGXN^Ie_qhdSSA zp{3RhwVMZssQ-$NaK!DZdy-wPOx|CyxMs3%!w`!(spjieEN7-gfy+U^9Q5yS(7!M( z+Pd1NUBIaX$Uujvb$~Y-ZRDE9u`v8^1j=7)=0CoLKWb*M{s_b0l6{FBFM}GLdXuUy zul(}L|EIk2n^i{=A@uR}CRKtkk)p~1p6BKx`l7~vQm;h3 z41UYt_YQ;K={IRh9%LJOm$x@*p9-~!LF6(lMjgqI8FK$&0{*qW#*Oz3xt5W?Z(Ed; zGGz+9tiGN&>vmkXqw99`zjZqrQKIzRK?w(l_5vkrLJOBDwgIybM5*B|r5irp(fIxh z$=u_Jh45sFM{_vZCR%+pEzv^?1t(Y=BNdPQibY9kaEM)XTwsDDHCt$ zF@_=Sv&MXj$o^KQ;O3uC`MRUC6ED@^STEJ}Qhmou^@W7^b6n^yItA#= zzTThf{rQ&n=L^zQcI>q^Xrm!Wnga?Bh2Bc5ls#b_lcwG1amGH~bZ`CXCO`6mh2<+E zLM|(s&!zbsJ%*PV%;XlE0zhvs@{e(Iqa6%FzK*!z~;MuH^EyVQCNaQnI$4>0%ePdG5Z zU}{j^_eaCkN=m7WBo#!cq8Gm5id;UL+q3s60h)_}`8b=1&5jn<(qLQi6mvx}U)ikwxGt@nyxm>i_F3MG#Q zDovth!jNOg^k)Kiz9rc~renlCL_x_dbIOuVL*^@cW~TL;U9Z`TUbBUx3=9R@D$Ta- z4(^^oO7~EYgtecFOyR#|#Z!_`+$@ITJZYXbGhf&}D=A?jm`4hbWC?0y0hW!dn)lid)CJ-V(~TZ0XXRZb^krx!N}nhoQ8tu( zY4uS~%WbmUCYQNQC`qIo9a1F%!OGK9U0`e6d(Ex3V>1)+mLALV{Kh-ZP4=MpiB%B@IHBaeJPRJlRHE_2MJeqEt1+^V0CBqx) zvjjf93GU3yOs1cu1~^-G{X8Go3sM92Rert7udgbh(m!RJWrMn_sqPX5G3j!on)5Pf=C?Cnwj>zN#(0UlhBoyK5yysF4E^UPVU>r zP?Qa18yQL}2(4kElo?w;G&E;V=L3Bn-8gnBpa@sLhj*a}21{~|vs#Ycl7^lH8{n6o zBT@}n4cMyz`>F=)O>3?^DyVJ)gy#qyoSe`dkb}Bk&Sl8Z@))_wGq>9<;3>LG%5+M^#FHR(qCPg?d_ z#&<_1GkZ3=)}`sXGDlYC$W@smLWOIp1$1Kqv5mpKcGyN~#d|4b93p5Z|N4NSr5o7| zch$3z@q-3pL{7wVp051`Ay774yXM+8FWNP?o(D!pXdDHk6G17P08-yL_2lC)G9QIo z(v9>cyU3i9zz<{^QLv{gXJ$^k!^9vQL_)tBHF={2}r30O70VxEzQ1# zk+)+Eklo}#PS@Ma+$*8y?1mq*c638?I?r+P8Uy4jr)%YOU6j*RC`-yw0Br_B_szju zZm=aExldLm9r91lo8`lqIlKRME+-_6E_Y~3QZn?}hPi`HeTAKs^!#+f>G!#r$x(H= zPL}KBCtN2lSD&PiE%kv=+Z%0L8$=xl&N7BIvgF6ko%uaG?*VA{`mPC0lHJ*%w_}Eg zP`0x`%k+Gr(ian_<~%(z3$zQg|C2zw*;abD1Y0u(X}Lok)S#nT#MY^mLm5Jv-<$pZ z2HKQ&GlY~;_&#WjvnnO0(|99$&glB@fSr#FwKZkel>Lb*`;9ZGRpnX>!SFtneZ!yx zCMcGZw$63r?I<)K6G!rXC;j~qESMvGa*$=oj2f4=qKM+^%UylB7xm>bYDEi$P;JxO z>EO}^RjJ9VXlUE+Pn4YU{@ym9KfgEWG`Q)1C!!3q`FHfc}T{)P97047?Zi4hFMHc z=PBZsw{B2ITyNd=*8PdM?#r0PUQ(wpAmVvC9SJIi0Y`3uRvI1iwy594AI;fhy9XLg zr1&9f$i~E^=XqQ7d719l*))HC&`>u(X-0XUHfGBuND?sX;Ohb}5n4fpJQ= zG_`(@ph>@~R(^j1bEw)!#}VcTjAZGw<@EUNl)_f<&;;wP zDK&?83feZsgUEbj2>owW!=4h*!}9&1tCT~GgwI3faoR{6mqvGKbg$Cr=8+^gDTGW_ zL+%KL0%41!l`UKA$7bfQ(Dw&~ZrW1f+|z6N{%aIG;MCX3z-X<*C4ZJ z9i=lvbnGD61_WgT>utkLM-n=QOnGNz|AtJpTiWZ=wVXfq0+P>bi=IaTy@E{jwP&t9 z^P)WyYm}_cU^GMF)eFR!Aqru!VNDyBV|%7P+cW(=0rz)gsuIQ>nR(`DlD%~do%5Q_ z`RUC38a%|xx@xXh&Gl6^*GDRFscXd>lE zc+WP$$jKBAr1d%S1YvC|=e1LL@c7WE!fBTXk}!??@gx%>M+BXAJju_I`Nz;q z{+3F%hUOZYmkiBqP;JGaZ{{H82-Qi!h$Q-unSgQ-n)HyPrG2+HD<=Jr=^;sSP3JK| zFWfa*cqLG;1nR32s7J9x8!4bR2B9Vpyb0tnv~W%;Do2nxH3bh7PBgtUMPHFgkv^WY zOfnVkabCj7@#{%umbGZEMf0LX6R8n4ZID!K&P;>K(V>xuZ;qk$(9E2nUyqTQZ@Py} zvGid_nW{`uu*{+xE`XbvkcJj@zfj3SdXaS{T0}OL) zo7pG_GH&Tca+Akr&2-~EmEKGr_)zJgQ=kQ2nLe$GtA>8n&|g(U-$@5Hsk4EeK&T5u z>QhdOTW^_3>Ci=!?7hh7ugH`e^A0i<)2Dhs)<`*JId9K=;Wf+btFd7Pb+c><-l;1UYe?{i6Jk2l2)ER4gMT_p%L4P(OnA=EVZp;=F7F zOwXkT@jEopiBl{U&{6?iqyj=^tXvahNd{8GppYSmkk-1TzVRV}-qhbc4%o}@ChOm) zrim)vrzR$3_wan)s)^}2Kl=wb*<-0^mwNUp^{h(Ws7MFoiXb==6u|*4CC+WjjqH%z zfYXyCJ@vnUGsx}|JxruF8Wk+#f6e;`zoXF-WC;qoi&aXk2&RJ+h1FdMFi=u&s1?8w4 zhz$erUQSMM(R%5absT6MqZ`vZ5Bt}ZGj6;yIMtaxj3=SlD51n@ zQoVR?r2Y!c%o$fj;Hn7xk&3`?sAxTLH0}y5FoS3ks1*^Uj>av9)N<%etNM_s<(u;R z7ru;5W2L)R57ShzVv?}4u=$;el&=eCFk@b!dMi}#qENjtT*A`;t%4vV3{|p#RhjuC zbqhKa-KF|aNXyd}w%e-^@y3e&$1h8kC33OTD(T}nH2;{J60VD=T}16gM6FQIy)*<8 zQIMPmxDSM8TL>C^E%{t%;*EB+2S%CGCoYIN3C=g=S=hw%Tz&8roSxm+++1_>s=3J= zBesr!T?J&IK@2WHi8Y5}D|UzrdJaz7O$V~sfd2`cBBGehP9%e#hhF{x&LGaq9k$$I z7rDc%St&UTdZ2?SI|Si?YNA+bl7fdqFDE!3=nwcNwolYfaNhH1F=fi(M)|}O=kaH4 zP=1pVu85!&5p+dFkdSC{5$M7LL|cQXTA&Txyty&=Lrm>ca84V_PWz^5PWdB{Hfbbr z!}BsPF&*b>12xIoIoHm4(au>-a!y)-aw#BG4T@NWCMk_p>Q>qzagf?`u68er1SJUh zj!sgY#q)$Br^Q9v^SEe|-{Cp4S<-sgu7~Ya58LjUntKM~>L4Wo!U-Xbspw0Z+c=a- zt9H|e4_lR8w${Wc-Hl?HbOujq*Y{Ck>-azxIACJy5p}lOZ<836eSIce4=*mIbZvSu+}kbg&(Z&gNwoswnjCV zZs6OL9)u4lV`}%jn6((G9J5$Ya6W$6#*KFDVw{s_{sm4owNPc*yQRo0&)QdvoaQSq zXaxrSNMO+a`p3Vv|NnpIKmPyu=l}cPrTynW|Mia>enT`gHXJ351if$r*~)+t!m#z~ zSzQa(L&ocwc<>mn`xY`uls}H2W-%X`%K0q3+Vgkr7rf$p=*IG>ERV`hcvM~nZ1FN1 zz8rEB2f;L;$f%I3vNhi3=edB5-J6SKF}f2+IXJ5+MmlT2=I0j|`vO=Fc@rM4i_5yW zoPKe68L&}CVHs0YloCj<14_XTwbq)+4Y~2Tfc4$bAu)=4kDbnza!SM^XT6B?^B3_S zfaNSJsc$9q{YX;Z%YenQF^!pXQcDKe7{SwUNW+pQ%G>6L5>LJ}VRdhX6-ED8VI^{y zCqE6aFEuzUW9Tx5{){p7WxRIkTBoYM)LKEb%!Hz(uqn5sGGB#9`QRt|-MHzFC5=_d z?#CL{P{~AoCFK+xyu`apy!#X4-Iwt?%$kKKXh<8#HhpT_*1!y_r{tR*%li8cUUwhF zLG1TLu^gEw80j>;zO=yxEm_i%CH;sj>1Dw3;P8roXTZjkchVdfz6-{wd(ZsBLmFg=;6bzo|G`#Moc-|<1T}f<-CYEU8pAt<3#2Ba* zkk&pLUMiH(IuxE2E2+2Q$E-EGc=b(FD$gGLE5EX-WAb>~3-%ejYLI1mTc)>HnBM*$ z^Kg$<8i8spAVUSp-~z?03>s-rJsq!`{7U?>-nsU^a6Nc>R~~%86nt zmZ6a*5K0viiNJ6xB*_c)V~H&B^I-EMzw(9gJ6?rm0L*WGjm((TlKWZw8uu$FZWm7E zimP&BRZhI5a^h*g792@5DY(y+mf#49wLr;Uw1!mlAYjv{9q!&hyhX4^9}%3N1gnWH z(uo`5CshA#LJO}8um2WaC1y<~fN>^l2MLf08dxE#BBih&OI1prolQUCRpf$O!7YYz zeZbC;(BL92C$>86>;Au6=u%q6F{?P{UBxlI)`o@(iKoIp9M;ZQ?ZZm!A~+JHxhT&v#|NVcIlQ(KdK-XG8Z!6gG{8NO)Wx8EFfuCI;kdb zFIA$7jbnXlbBeu>Ouf*Ca*37Qu4AqUBgJ?kGM^Z8MVGmCnOk3CZhZim>P^ghhBTCZ zY4$ya1UZwZnqn^bm}Y+$nf@t>xJ9N%y>g}y22`Ze@>-tJ?9Ys+h0KM__aKvUAFX!= zD{3Iv3uKQ1UgNZ@*6QO}AjB>*<0Wi0d#eQedTLGrMGJ&>+BEwFGR1JYX_lMj6>gdb zkjcSoWQ*XVb`VJdo_l~~W%Qi9c|NAY-$kZw`rJ$<(H~17mT3$nKW&_Ss-RRwY0>7Q z%{S2|=gQfoLXH$cYKu^MFu)`wR90-|n5pdn+QcnWn#6y!r)KSidmAufn$f+%p;QVmBMHfBq2Q+@Q#Qm2tWo4@Hx)q+5iOpE%;QU- z6y28iZ;Ah2A^v+{pfwF_RR|=>3W?ZeFi! zt!Itx+DocTh+(SZPebMtVgt6Y-kIy2`KEW~G=x^I1B|iF#^3}Vsez8xUA1|&1De_o zWb*wE3cu)jo&!Od-*fPBWS9w>RBvfG`kST$ht|IeEq95H zG<${7?1A0T&{nIK0MVF0uo~oL5l6f&4sh z?q5{C^$4Sjul3Mc54~wU6l%~sQUcdfL24vOF%!h0bc-G@T@jTno6WgE&=4Q3Y(|p14+{a3C3%FBtZqnYNEAVid0PY>2GU#r-U3 z>VE0|%~2(}%97PCS?#-IwJ8@VZ3L)V41_)^_n9Cz587IgVt5FdxF-?%QM`xo>JuYk z6G1xdc=C+kU6({?Nrc`e5%NK`T5b>uPtL5fc|R0D46SoSj&?}Ahja<|Ig>B6VMS4o zB43>8$;2%%=~>9c5O$&Y?Wq}Oh2dh&#hUM7%~3ef6bZFbr?3_WI0pufoh*-1@Yv-< z<>#gc`L7TzYTKHF=pQ+oa>A5aQ+ z5Gppi^)ncToHdxT9?~4BTr~YaoWH=So89^rgI-nd7!Ws$zF-(v`b>JR2C81{d7<1}{?t{}Vn7&W77DLpp`w0e2GDk{3P5J(m zT91>)B|BKMgEz?ztVbMSDD>P3M6rX5BUqBybPNgY&;?~;@BUaDFJa@!X~yY#LBT+X zA~EQRW9|M8!@Hz7A+a4aG(zKSN!Zx zDVV>&DHqvdP9uwdzB!W$Cp$0F>#6W)x3u!!SKj+e^4=c+=NPPGxB#^#AZ--L$Q8O+ z%@VPcacr!$3;iUe{RK|H@Yb8t$oOkni$S9%Bn~HTYxnE5Z<*7{P!~8CINt=$*hi+R z391cevO60Tt_~8yaF(9E9#S8ueV#DyFz06Co}|EEmQD_&|f_ue8hi3n9M9#zKfyMX!y3 z=#-)b31>C#KF|nwqYj#lfFJn`i#HcnI+%ihxMrem} zg*0A>ciy3!DVe0oUmILy)fxDu{?3YQvQ@~i3K?Ef$nZ2?yQz-o9h7HwrjkLbH3G`a z2P@gL9b4)?fLGm`eifbn2rn^99udzot$h4yXQ_KT{kousHT|yX_f6ApE=?+oi!mwBiRi85zE6lKLg`$o~9AezV=2Mo!p($)=pQR!RAvreWbcZ z-8Jg|Q=@Lny-92XY7A2|A7`}+IgFM|i>;&fW3t>`z;3fCGX}f@mc zG?m~h(`03uydu-&`KM_tTw7KsIF-7c6})?Zmf3sEL-X0Iq;!!D&o(;8>tTk2uqRHq zHT?23c;$W1Hvf%R)gUWWbA@WYBvkWhyv~Rb&Y8eljUb5_vW5&8C1k=Lb3YlczL`uU zF$Vg=YxEG3MULsLfjI69kZ$8oBoM8)>UyibFuU4i$F~Y3KoN&I(jHd zCD*e7t6RraQRZv>rkVuD?fA{-UavmNdiYqA)I&8**BlwZir(NTi(;< zJ$;4u^l5(OIs$QT(6!cySA-H%fiB%W#n3q%J;93Z;C0JaBgTJZIm8%AS(Bf}uW|nb zd%JPsBw-autOALb6i7S`*xn_klqzI*n_e4((uARU(=^=EXh+qCJAkFniTQ7W)fn8q z)P`;;q6Os>gOQ$z6r?~)&%gBiuh8>9F#LwhHO7K~k_!kEL&_Y12uqlCOq|O>Y%1Nu zCdLbIq}OAJg7Is;L>R?L$raB!xDxHVZ3zE{CwnsHb;4OEoL8K19)M>uiMi1%m%t2? zYJ(&=BY9)j=A#!s`Zm?OZ&RVox2d8Se`$d|XtY4VPD`-&eQe$;flZ88WA|$8eph3+ zNs%yU>VIb#FG+`@vsIt74(F1Ljy*%u&jrBu*1W>_QRVRY3^hy?=1_UsGj#th^X(aG zB)q~MR=C3}!X2J|hSm{dAtvatcaX#hig1EFii#Q6ajf0&tL){@o_DKvR3vh^y2{l# zr1)`KJqfV;!iR5wm1w&5Mr&{MPwkBuNwLiABp(^XLj>2ZP|Zxxje5|t0lQTaBOxWf z0#-Dluu(b^-or%9*5{{AsZw`nt`tg7 zY!4@If8cRe@!ypyN&E~L{Tr|;#*d_i&q5i~M5M_$p5?Z|xPO|#8@~;QU{1@>x(uza zFtk2Er&K87a0OCPm^V}?F$zTN^I9V*wR8lX$e+c*Kho)TNuq`*{AI0~2@HWKv7EL1 zP5Tel_%}3BNn>2lT+nomVaVNE6$)jFyOjSMc@<-hNZ?cK52Kp@ETA5X%CE$U#bJI$~-GPX?#| zknPKSeTHHniAd8L@Lq5RT|?~}YTq@~rrKg@nIVik6%8zqPzY?K(QEB8=+UL_Z#|Lt zU2vxD4%7L*{DV1Fk`lR`7`(mj7{6ssr}z;Gv(n90y4gF@&2*4<_X1q2fz(pKTWHXn zl9Q(q{86RuZ*bmM1FCK3f^v%2f?;<}C`jQ%rS87o=vxsRMqII=D;D%!v7m0T_RI!@ zMghq)$jn*+l^#Z9E}b5gFZ{x0+N&^47u>?8TEZ{A5e7j^0h6EDlDL0f`PTJ>>b9Jv z%USvgXXyj0+8k?ZwN$XwX1{PN;8U!N*>dBQ+R#U3^uNI=_r-v^U16%^e>U^aMU0TA z6Q|n!oWXC*DM41y;0hXiNzmW};ItO37BTRs6@-G%^6v%>scVbLIzK9+|7s|`)AfW? zM88=lLxz7wfHJF)#nZy>pD=h^LSGvCrJ;Y5hCX*5fvG{N$w7n^66FE8P|oTy`oqr9 zU&z$E&EGf`MZ7W7;%uFmLib-oEwdw<$B@p8`;`4vE!|u>jZoFsA!Qv>-gHP&*H&t) zfRQ_hw*)zIfS?|XHG3Y1Y3J+W1VJ`^}dtjhN^46;&s3L-t(ZCxL z1S>3~b{g_%(DiR*-XCa{HpK_b=JAS539}{%>9qUi1Dtt_%w&cuPhsULydqEGk*B5= z962fw2br><3Mn~(4!6wFy*V94=KX1wwx?NEj9*4<6`Fh7DB+FBboxl>U4p$O*n5Xy zFLUm!y#jX|AS?q??*c5HQYqQH<%7t)mk)*)@lUz!%{!CCIsWH={Lg>?Z~s5`t|rHE z-&dYU06#@Cw~=J&{zrIFW`60OZch>i?tcb&+Iit^p{Qc9>RPXv(wZkkHVJ+;0CwblyvLoQmi-=|-HMJ8WxCybie z1wU!Cf)OZj-qz#=WK#C!Z(siQH~HH)#VrOxrz#-2ZrNWskZv~?&K>nm170OuYmX;35b6=g&L($(Lt%9^xy4e zm?8B(NwjBaPd7T;nDnk32i zGKR^d8>NT=iTX9jhZ*Q7GVg_9UYS&OdIgy!>&Kax#8idw#NOV=ug|Z@G`_kB*NnSn z+|y^=*ZUm6xwP5hfVCv4Hd264a)vRst%;Xs)25%ptJnqhit!mmKHj7>vjIiU^S{3` z`4TUW?ef^Z%VXQD4b2QG2WXP5P^zMkdPW&AgSOgHCguB1zPRWPGR4gKHse}2;}mmG zt48w2q0(QQRs=b(EQFPX@FQ6WFH>o)47F_YQf1Z*w%(JMGSW63cZxQ6oDNvr5s?Hl z<838s2%u;pa28+<9|HEvN)$=P=|R}Vt~$inNw>pz88)dCSn2{Y8GEorJg zC~Xv0Hc-lZ%%}SdUUwphL{a&MS5rVybda+q;wP%izI6|hldp+*O~n7yM2xu@*TN~w z@Fb;_R7I{^n_Qh}fE*=Qc|@?fW2_gR<%2iCis_Vt1J8QGz64kTTHS-Id+?v?9>mRz z$7X3n9ZA}VRI*Ls3AXHgt5}ZRbw2~xoxQ4L3IAZ&%sFQOI*(x=PsHB^mRqWQ=H=EpQe+=#u#_P+9OS4C{{b@NB0DyG;rP71VKXGp z7^hL`W{vDv3icCt-FvIDirek2s@ZuaP@A2G*T(_%Uq)X9Fw6_E3$Xtb zU>R!FDK1$SPXbg@t&C|jWyxD^QFPb++R><#8W z0jtwFwFcrf5dUKXahKepr?R0XsXbE7R#NRbTNJNx&AkM7A+cC$3U-*%>M0=yJ zfPP+}l6#(wpQk-lUqL1>5AgB;|63klBiyRwk}$X?Y2c~G*3y^{)z*=*AI0natX}2) zrz#ua$CidN2ne3o3G-N5`nsjjUq?P`tGc$Tr*BoCKxQ{$fXx%tF%1vX`rw@tT7%5d zhx*Ys>HVzUX+_#`=d*}?Vp25AD$aIVx)~ovrl9+Jldd=EPrON=;Y@};tVJ4)<~jx< zMebW7F9S*$b1icenGbu^_HqaF+*jU^X`EFw08d-TJgzwWChrn3E|=hP3I2pj@b&#E zvDT4Wib9$Me0~*5I8VvL-DMmL*NzL^-=F4-?jEL^#7*8+Mny5y^QiQNAs0>8qjWt= zf8tU41eIp+0h(Ka)^ZZxBGnCQLRG5H;Q+^+4RL`-RJtFRXlO)FdccpWgHNOuE>XA#Y z2f{z`0(9Z~RWbWEB4!Bss3hf_b)JZwhs?*E`E{9M8Y{4D1(y9tVA&JXEa9e|DkjH5 zNf2_1lBX7wJ-8K$BMQ(JnR35gEq0eFgap^E;xB0Ow6B}7?;gGID=$sXk5yZWKhc>p z1Vj*W z8gV|(N%=a`h5)RQc8#=e8fi6pMN>}bj!D9Jc6n3kXtW`a=XMO4{Ci^k8#2W%xYy;) zdVN~{er&Q6Wr+A+_L6=@rt!5&YH{Y`%y)36*A3M)C*P)XFG@*)h6zcqVa8JQz>yhV zfG>J~srlbg%b&>1MDY;@h@d0}AaL65}32mEXDYJAWd-^NE2r+-ZnL z3ZtH6i<(?pO?~=mk-87t4uLaY=+RzNb`Hvzk>JxntC>hp;w)^wGSDI|C1@!@?^1#W z=e8+(Dm7yg8a+7^q&5^BExP$JCFmhC@wX-6D>6Cqhej(ic!fyw8KP7NDdR3C3}jdk__|K%&loXaEgK#@CO>Lzy){rniGp3$b{^e1FfpxZ8#%ppb8*nRS}>Jo9N1P=2h=ehsWfM~-zRwywl};!5lZXkv7^o|%j$If>|& zB122q6-(Q~<4D{WUQ{o57n*;m0#=gJK8dQDYk2e59$5v4&tkWGDsrrddI(gpupd;a;<)I1Ns{)1*H5lOz5o}Kg5 zjK{3`b*E_v3QGlAD$tu$pzfIg=5gi-O(HR)f&x+zD^#p?8i(}RTi(dupeepP(5j0n z-JqFy9);0)`fNNl(0+p^tLkFS#hPzo%}mm*drKLICMi<}^4wDx=_B&MX zZ_u1o`8xseSv=_G(wq9MI^>LeRzf_&V~O@FI2~r4?*iun=MRAMAy*DT_658z%N?>^!?nU-Y@A?X62_6$FevydSkcD7@c7gU^ z0&NEX9nn)Z^dv-@YOjzyit@H`@p_nN@2*=kc5Qu`$nq_BdX_2}2wOgpXYnCszYW2z zW@`vuL-0=w!7oErz_6)tf;wNVZkB?KQV4TU^R#yDVihom9JXI&pg_5?4NvuK&*BSoRMOY!)$frVc9%b(cN}1w1 z?*4bdf|^|^Awz{zH0d|iZ`B`LiE&LCKM2`ew*C-M?r9(6e&pf^rDbW7qLQjJ=Y z2|Ab7u(m^|Ezdx9uW>tvO56|+c4mxvSe+0(x~N6T~c6P}}&A=_&0 zg545Z-ICPesWi{2NwE-P3OQgBqzk|U|L%nB&IoL*0k>;31UFT34LgrzA3J!zLN*A^ z*ZXw6Pk-Wl`Z8qekS*ufl5N(KkZq}`j3kYLu|>Ea5R`sF_O3%|LU!kX)KJkrK{k7i zY`}KjVEovl^o?abLKkEgWdAA1=H4wTZfO(sB%^I<7IY`&4MR#aKaypAg{<5uIr|0K zowuxIyS8ut7Mc*9nMmk7djvjKff2r7HXMwW(zKMOpHP}!rrB*Ou(jtT+WIOuW%|nzd{TvJ0|50oi8`XowS&h zM%WA$Guh6){Qr4+0$(CotW9YN0 z_$^HZ0WnKNb~_K8k3A3H-kfZ%Yk|5Js6VkleFB_Q@-a3{8yF@TnNqFX(#T!w=Hi+U zffM1v_urhn8$y;X;3Mh?fn76m=xL|nF9|}ytSg6X<&eE8hm5-fYyc@TNs>_|xokN> zZyCKRk{?J2yn<66xdmxw!;*8@M|LLyW+E~@?>HRcaZ$uK=9Gw4<-4kU-&N(y1X0Qc zDF%%suu-ZgEosgjTBRu74}lXe$aleM7u>1xwJ897R%?-nnB~N#h!@n_9D-}CU1RN= z##(Ga5*-uE>?1_kQf1}DwY6F?q8*8D_yx}UdrsYLim;j3`N?Nbo|!?z-wI9x)+Gon zLFi3_&=%F(EWwwqJ;`uNHAhL>ku&EJy|hE%oRjTcaN33TF4R2ivptv0^9}WQr0TvO{P;1R;I|&i%@W>?Zz+ zIT?Y#Nl!E(yaG#{?mHWZ&}(?%4MX z=u`gnjJIWWS36MJZP?cU;@YtSH z9%YQ>i|m*X3`OV`ScGsj*9HNc2Tpzn&Tq#mehn2}=v?T04?4j!n^#OQlZr$~{pCW4 zu@M4}(Z+#{1-hX8R%8Dv*ZKu^G8PQzT5$azbqXjFlD*fz=Nh=?+BMg{X|8qPmVK18 z=@v^ zmj2&D^Z(fUmK?Wzr`r_~sQ06HBZ}hwmvBM<5_i&3td_6*cYu!*10HE~P{mW{F`@Zp zXs)Kd4GXp}jf)ufk{fNssc)LDeK`ru_<+ZA({`chKSsdzD-!Cz0nSFNS7IrGLt5K1OS)lM)+H9*L|Q%NwZ{07v-t>|djcUc`Yc@WhH0O(RzBu3W;;fsGY%VG5idzw9E){ANTD0p>$mDjSDB=cAd8po#eQ*j2 z!5y6HDnO)&R}D@(E-U=nBMPdP^SwFWn{Rq=*1j0m>?N&A5f~jVO}O-h&}}66^%G@< zG%9`{W#sapYWHfF&oRK4 z+BUjG*9A)ER?C>0mJ+bpDX+Ea2R+ar+~B!aSjf(5_cy0fhMUTDHNSdn=G5OOXR0I2 z!8r%#n+E496&LALOrRB!>Sb9vmu${U3su8Y>LAr0skVPZrr3w>NcU8c<&&sQ1Q3kt zkQv71H2zsMNNcSu? zU@hId`bJdImur#fAFxyA%SOoe_yfI#)tcdDdRje>m;Q=OLW`-_n|i%B>Gjra<7yoX zQ?EtV?4{NwWz(>ptER=Nf|aqYKDeHY$e<6|Ic>6O`rRa^FtYZPMJ_|;@k{dyG9z<} z^`=j)28tmp;^+p-9)cquZ+OLXU<$xeZHC9Mi8CXrq@GmrgY zUuR~dOpW{0xW7x|Zfw4A--^24VlZn7r6>YS*+f=9mlve|!(j5)nYr&kk)+H!1!U>u zpnhG@o*&Q5uZjaQFqjn3q=4Q;0j<U2xrLN4B2}{$llW}MxI^UPzY7EZCq2<63kMv#cFEM zS3M^|IK*r2J5s>G?@O+0A}bo>RmEd|yySizrOcMIc5K#;{adwTwXKfUhi7a^`f8)H z_}WXZ(W(J2fY+On1ERf`(|gJcgnMt%Eu@zX z*e9N_V&;<#o^0?d*x;u(;zY)UnwDrW0>o5Hww6UT64_g1JC!JZJYe%jS<4r|23!2X zIk|ZVTVC~qeG0JYI5* zI((H)@vbTK1P(*U%kcUX<-`~>EMt)aIUR4rUn!?>pCaHX0)B}I_<6kcineGLCcz>LYl#pkzKAL# zEpe_BZQ%7NSB3Xpuz*f?0it>^u%Yl}cs)+1|AJQpa`mYVp4#A7XoH^yY(yH4xLxRj za>7+hVAdkNg)F{N#OW98W5DjKCd4#zsT}vC4!IW5Z-MW>ex)xy5s9+n(smjq&TKG`UBtHdDzavvwf2kaG zM^<;CxXKpy6uIQ=^LjI{H?O$fd_x<&!lt@0mKY1J$ZDg`kcK8gtFdvjQyKOeKZFi{ z9h$ixjYKA&L(>zP1QO`7E%zB{rox2ggyt)t`Sg|xo!oF8fNfGlKuU0j5{!W>lD2kk zmgd8KvZ2-v|C?yE0?VH$-(Ts2A& zj+fs*8iOgxrs!dc9$q1O_{O_bO)$c!^dK9Iu9V6_MbM%)NLuO%h5mowe5fB3*`{_=^T87Iqeyj|xd| zYcB6LP&mhDF6gafKT$6$J$y#lt8>krYwl~-+;7ZGfu@Ub6s=N=;D%+f=B2lWp2H(^ z5}9<+4I}ZF#9m;#D;AVFU7SMSiOgW1+w9zC-?Yv47~E{@g}0>^Sq5KQYb`Yv+JX|u zP6Rsqhs=l4gukQ@vL@tbYmrS!mE5y3rn3?WdleI%>QP(1l zT%t)9SrT-sVYQw}x#tg%A8m$zL*_V;?#xUJrntW|5!9Ij$nz>_A{@(x{vd(CVhVGo zF!v?G-0y&s7DQ@T+>naUsGwMbOGgQZw$cJ8l0k3ae5@N%-_^`p3Va6LBgk-&qF)Kl zsu{#6glA%+FNpxpF4LRf-`r|CzfdP%j6VJ zQZ&D8seKBZAvw<{^L+BI^GP+c5b9-XH(4J>NfjxQ71I~mEKf8Z@(1XLJSJ&%H}2lT zZcdS(;AC?Y$+%2%i*Wqp{9|%Dx=#Dbw6DCvzVeN=HkY<|8wD}lbyVz2Nt0e60j&?J z7Ec&e_yc~DJ%0sf>;~Rjh{-+h9ziU@h~csm%9CrY<_rv+fq}0G4EzQ-8-TY3yyQ5Y z$SPJ6D2r}2(^p*Tb{d?IReZVcB69=r`+bvw6Nr32eV3nMgeZ<>LG)#IDthY7^PG8} zFUj-#20Yo;NE!gUEw;UJ$*5eYrgB@Cj(qNt;ve{!5{e)A{leEe{SteEAc~-IgT_^S z?K86zjV50^`Pw(}wLZdk zk-Za~2{4Z-^O*9sV+yRX##(!^9HkP#Yf0;^MAFK&#o{cd!1*&F_pjiz4}d?x$woJo z+)qU1m3%7OjGnto&#ml;6tz7^~P8m@U zkBlh(A$wW5`kzYg2QulFmdo$8bUOP~2TgU*o76#s9i(|HZ5<0O!dh~3DQnv{8<8fQ z{S-3g=#297Ir;^eW{G!;*oZMfX430s<`Y_X%Gtv-dzfC*!}N`rDb`aJxu}a58KKon zmsYl>Yqi!{&%|l+hswikR>o6v?}mboj&di0D1y{89py5bHjgiyB)@O8%8WqMBsNWA zZ!(E3ia`~qaHm$JE>coEmu}9T)2yB;Sh~pz9%UiOXN<}3gOdQ$<%2o+uDkB%M#X>(y}$x4YBfx)UO*n^?~YLhUy)6 zUYzKh@M#qzPewEo#_Nup-udDQ!b?Np5yh9K3SdF%O6HL( z)>H7b4|+fd-QY<(-428RDff3LlZlyvAzl?e&3w$({-Ht0w3&b~6A<2(fY6=2w{~7-0N~&XG+*4&-oI zal^5E?`v_xu(A16?@jgIE7W^WN7}X?STV4`f}@Qaq2!iSmd#ifO9?vn8uf>fw({3< zUk$;#lg!Nk6It`Jrj_Gi`bX1>iRTmzP0`RRL_<#lHcTMuAdQ+17t5k0bD@G(m%3rA zE1Wuu9s*Wk_be)yuJ@!{i(o)jva70*?0CX{krE-1;LHG<8DKBT0DBs+UQxFyTvl-_ z!T@D4(o%ulNUOGfj!-%R>|eavGGgNI$5Jy0faHj)y3FjD?EMN@^icvc0XqTvF9CMx ztu5$Syn_~L+ghr2D~lm58`Re7DM{eCzdU}!`fkeuVFrFipDTZ=QDYJj6BKTN&dcq{C#?yYUh>vrp0jNZ&rs=oqCbV?9Ldhb_%cgqYMA9 zc-^lCW%K+6ui_&c7ws}i_!%9q!L*D{%jioiqtCCuxUJcJDP8(j1XnNF)5`);Bgt&R zbByp2UP*t{7XFS`Bt+snV9^m#&S#G)Uszw~AO<>54+R?=xDeV3JVTiej^uEp!f z6q5=iqD2|OVy#tKd!DkAYW|>iAB`Ws?2m4j0`_zLCV z)8o`C6KI2?8_CGgT}nj964W6ns3n{eEd6A6&puZrMeg?+6$2#*mCNw@#QN(7GpBRr zbiN{|^J%=QZ73b3MDJF_dn-$4FP^<4aFaY&7jcYN+g*PJlKie<8spWS_LFu0XU|ns zo9ESeUj3)et82Pxtx(A8Rs=9h)V7qRTIdR>%qQqz8ELzZa*u9wFz)Tc!iaY_jVh*F zq`sA2N}rwFvy=NJo!rmQ*XX(mETvKFMONI(lGcmr+Jn47>!+=zSSFXxE+-WiCF1|7KH`r78!`1vQ_u8o>6uV!bX`XJ z8Ap*(R}orA?ly;8)@*)4&;L!l?ip}|&F=XSu4!&$*BNm9_yGIIfE8DmFWC8l{ij~A zvG(W=Yhh+DqSQ;Yu^>~R)P>eHPPEF%h%3|wafSMUvVYN07Q0_yhxG+hL-nd4Q9pjc z{sCA@m=@P*aeax!^&7KvbAhf>3+Hg3Q}$Auw$gfvZzFH1otmYG(A3;58J0}QPiO{M z7@^oz8NUICVy3Uq6ats2j+p9*SEwVt0Zm_}Enc;7bsI&AR%#C{sKBgVakUdkE@L7- z2PX(eU_5@G{F6zHo*Nq_Rb}_ai7=XD?%0C5ATK) zrTs7Amhz>O{L_jZx$Ns6aL(zk00IZ+Jnw4t7i4y{-irl9$3Eum4h^M&XZ0w3?qA1l=Oj>>>w~TTw>)B$HJ=%`6^9=56WG_tP0SN7d2Du!UvxC8lqHx$PC7}oSVo; z)y%j}=3gUPES>G_Y-eB9&UWfenka;4f)3pS5_^G*(pamB(7E5{t)j_z82T-ukss?$ zW748Pe_T6z`xg9r(G<;TH#qGEpJF%oi=xR(j8W8JB`?rs3-mCBZF6fRZL@Pqzujy5 ziqh|Gd2&=VMfvUS`~9OSLbdNs@L^=$9s+$QGs0u;PUi09MY|J{vF7js>gz5M>IH4z za;_VX)`k%A2?xR7k$L1GxQhutJsN@yjU_D~rJ4VQf6DiEmTTYOOf)B&PeAi-4Q}@# z*)|7hDxlT^`m#Dy$mY7B;JKr;+raV#kATH|OXL4vDfLvhGRB7;x%h3-{I^m{j7mIf z>8z#CsHJxUD^wXO49V)Cy)|e-4U+omxV2@B6DDQ&itYuoKvS4A|9{2ptaFIux|bp^p@x)<^e^L-TY?d>z=lh#UY*N}skWQI@)E ziXL|M{fl6z_*P-1!f2}Ir)vJ6QqAuf_UL-w<)aGA zhF^h2k4%4Hg}nz@7n>`YxsrLtO6Kkgi&m>NDNxD*ii<$6wmbMzZ<@4jbxz&ziwb+> zv#p-;nOhvLi6r$nqlUZg()O5u3G4*+UjnuXby|a=50~A!jG%W8Xu7Uui#D!$EU*Nfsuy^V(oEYEoRO zbav)+lUF;KIf=!81QL4|Inm={-0qMrDOpVE(v&VeL%MW#L+tFf8tgDcRjg!U=3JZ@ZcejOu4K6#zIK7-d^lu{S#xOs!NF@iPTs9sOQ7TyyH{4=bTS6Cz-DybJN~>i2-hXpBXJX zqb86kyC2KQWt?zdc_Z`2N;EHcV2~{lDj#=lCa#(L#OPr)^A0kVc)IXT7v2}S@RmBY zQ30CU09|r}j+jus#G0cb&WHhjN9JMfaG=^}H!Hh?nJ4DMy4gF(M6@X`n&P5oh>Lzv zGs9)`QiQhb{@9~+$b}YIak1{iq+>cm} z;zrT+%h8#!SJ+#4;Dgqj_mGJ^tpul);6G(0Xid175{R}2TIJBTJ!C>QUYe|1*13r- zy{}4stfY0JBUys0e32z+dgTvCEcb0WZ`&|@|9zIsqwaas{hXujU-Y<^8Pe2&d+xR< zU7?z9P^OUsmpB!)|5i!m`YwgvAABP-RKA{r?kh%%lvmD$b`!E$NoOT}LM8nLnakTI zQ#%ZG2Q>=l>*k=f4lnAooQX_(BU7*cKI@`KhuS6d<@ag3v%NajD|=j?851*O;yD=; zcZ=d34L2r&${wI9yJ^w3!CJbIZMis~Qt}aB=(@3jUG!jDWXf3|yoQH5huOm_=`Y-O z|1$H83Y@ZpDNA^fEMXfmf)<1|b`J%nf@E6uWee5lDq}lWO8LD~UP1FHdO|EHKbN1J z8O|h+8|2=xVhP8&{G7|r7cD=7z3XNjdb|yWmObN83btiS@#ekJ34czzkX-P3(fniJ z`K`&_t-?N=+}*LhRN|#87Uh`)>9;zTR$h| zliN4he2~~}NMGC%!c_@b>!s~%G3Ip6ozA(>aL)Y&nyCZZIs%wcKpPI|8U;%fkByhI z?5EJw_hreCMbj^O6xqG+J3r7gk=^CmANSL|XZsm4w<&X*^15w`aVi#YD1-Jfphy<5 zz}VJeYjq-l>5WXjb$)$hWMb@S{!ug|lq54BrhmULAHse9H0MwAML*4z6RAr8;=V*_ zh|q^9@Y2^+`?`*PZqcdlwtLr#=FvJuGx+nT$;d{b=?CkSyU@JH_m;~hnUl;Hk-3lx zx$Q&^Yi;Y;%?M>`mMf+pT%pb%-g8tFYnnam7`s2vFb;;e93)yqUuYnmo6h>J)0E?wBr(^|Tr(5#WDb2PnO5_k zIscij`e$ydvQaIdh6uXfr?j!>=d1Q=BXHZ!Z8YP8S8Jx`1rN_Th3$*~dnCE}i#M7y z^HpZP%2V=Heo-?~XvJa&+hSJ%b%e&a!Rm#z3>-_H>t=sJ=FvuTSGIpOCrKe=ey!9! zd9F?7+T>Mh6GC2@b%VZ0?h_!~GgCVF7`0+iBi55-%GGXG{T9 zPMQhjMXn!O#|00`G>fm&AfoVN|M&l|xloc!)7oiT`zq5~8f)=t3yi=$7cdc8(+v{S zd`VtbJdxx1Rx__>rf9s!lYJvIL%!}(+ycv)A67H(nAj%DBy*DaA~FqS=+;*l==)q~ zEYLF**3Fk(h8wqYqP@JK4ALLcj3P=uC${V+Dxwb)?cLMO?#HB)%t_{J$Xt0F&a{GJ z?KQI!I`e)a)*9pBCC`PUP~Hef(Y(;XT*xevKmM8FyI@H}9w(>0;|3)eWu8>elj;|p zRCm?I_9hlBR?wwrm(y<0_e<+GWNham02yx;O+U;nG70>Qr4RI!LVsL3O7KkqLViP& z!^q|~Wo}bmv`tw9LwOKjY#nsl7U*jVV1}>J(xXn9V=~`H^JqG2Y#1N$C|(t)?)*43 z>2%d(my9V6n&O}riGw`XriBdAhk)9$LDy=~!ZnzCBR@5sWxm+0ArKuoN=LAK9-*LD zq!T_)9CW*Ce*bE+IL&@`_OmbQXSXspjSjKC9ibpYi575c9ix^N&#g2~-%qBG$@Gii z#SV^8JV^LMfF|TZL;K&3oz9Nik?vGNT|(w z)!L2lR7ZOo&N`gX29?GaI87wEv>sMB32#q=zQb9>5);k|=ZoN6HWM6zP+KYJx_bmg zH{jTErQx>eSvc*Axt?E)E_wi`n>&51PpZg@LmubtPI$Yi{i|?d&ZOL#l>4%zTue;d z+<~$==oSH~+W=u!t0nim`Ny)E?Wv)vXd#Wf3O-JEsvMRk(`2e19l=_bES;Ns=A?E`YF{*|rA-r2n3vG>-~ z9$6o_bJ2$=sI(L{Q66UGRkue$-^=Fy-Q{^LHm}8=aV_?X@8(u2s||sYmY`V#iM@kl zt!-5v#ixvE_k@!xPF{X7x!@6+g^V8;)`awS;4Jj8miDeCily6xbHe!|I0IYb(Fr!9 z0jf&SLpmfc-YA!a`YFZUM_BcbaN=PIin}L%DE0_3_qlE012>#^G__QyGirWD&A%vW zp421T7=XkE+GByXyOc;n6&$s0cq$0ATLD!QaMGO0_$;yn}oL`a{u~q zCgQa8nwDNKv-HBOO_;!HBT!0#mg-QfvRi#^o1Qw|+~K@BsMR{u28G}ky8}WG4#ebm z)a@n_o`$njji;;EboF|XtCw&LZ)?B^W6;tLz2gRpW!3OSnw%Te#)YoS59%TZqgrEf z{@9{KTCyPG(Ktx&Ve^j21w}NThbZ$99C`m&}_#=Z%F*I2DVf8g`uVDPYyzZAZZquD_ zy7N85o$qd7qie0WC@g&kcHOt8H9D*rD-yHoNs;bNV2?usCEfDlUfYbQkb?D5z~18w z#^O^3IAws(kOAJ!s|WVY*A6kNK-Zqo5f|7>sB&wg=P9@9o!2X_ME~RUAW6`0|1kdH zH9RV64}p1DfsLEI{#9UIQ|B;v4uhXD489v!9HhJr0a;c8-H4zmDI~TuaSyZ89q~AhjXH7z$l1(mjLxD8t?fW60}` zphn3b6EU+h78N{eg?&hJ(v`@$5;>oe$oVi{d7wL*LDsGyp#`d`f@9@cte1#Gu|_*y z@eW?ENlxrc_C67-@Q#+Ga+c)u$Og-5%k;ZUzt1rJK8#lzrMA8L4BHqWT?10m0E;;G z9=MfbR$%{~$Z%sImMfp9l3Mb8Aa>cC6MwZdoP$@t&#&J$SS&&72D@&s|I`h(jm8u$ zp^P#?+$MxE0k$&cB(&nkUd8?1W6fVACl-_slT+qiUdZPWY~1%Belt0t*)mNm)5O1J zni!D{%d8Me1Y%kt$Hsu%arXsQo`?Fmcfj73oakx~ljYtZ_#a@g>?R5=<-D>{EcZpH zZ+`wPZ)5sOMOvvyuSiAOItHtCP__m#tU(>PLET0-?jF1ybs*kJMath@O@Fc}C*db~ z$rKS?ik>z8KBNaz@M6=&rvDV1R;n|z7&NN_lD$LN+#suOI9#IgvA=S^8JqpfVUZ6?E)A$S>rpJ5380XU~?T8#qTW498H@hb>z_(p1(Mt;Cb_y$hBQC|8s>(Uh~ zp;O9da58!D{)%@VIPd2}e51~AE56j;rS?8U?fnTliF6d*BbK;>P&UXUhpaQyEBU4e z2HRigy!~5_SF^VrL-GA`x*tKzuxRRe8KUa5!0ChMo+Ao1 z8-t9#L5?0UnrwB$nA(m}C*JWKiC=Z~x~P1PDSTs6i=Y=%XPB+Qb`7>K8f?ex#5f2> z$qvGuAUivd*Cwqt?RX5Gao@v0S43QAD)jDQ*fk-_q|E=RCiIOu_eQuS2`x$JMUv3$ zREu^3-*!pJI_{-x4LW+ZE}<=tfio|1yHiGfhZcSTr(lUsTj%b#=Tv|3TuYLRITv%j zh&iQfn@4RhnHXd%8^ksgM8-(f#$iXnd1vX&t7U91p7~zJw(GTSs_rMwwfFVf?~+iG zECb*&06xV4_=ByJY4+0EZlU)8*!P~#zaiObQXGHmgP6`t( zaptY_p{=vLg$%D-=el*i;?`L@7u@#O?jdbY$2SP|36j%UVz!pY(24g-pW^CZ%V{a^ znvhCCOC&qZ*7rczcI;{2i#Hc8;_}c>X zSKidC?cbaj{t-&Xg%cCaPDADcnJFT;?kMYy@}fJ6;a0rKfN8V`-phn&8PI!nwpItu z0|mpska_ctqVYSh_s@xzGe5PMsz{_3J#XE7gfo?VapvO87jdR+ed|LArbGqti4au` zN@m?%@U!=0oSFBkDEva#r`fRgT~o=62qK*ps_+PBMxnK5u08WbdnRw#xsM9$qwJ*< z6Drk!*0t0+qH8};67vh0xA#oHp4hpY%ijZvlp<7<@wLcgUK#c)!~Pi=_CMJ(>sG0> z3Rp!zs5i)2EA&C$=QLtI5FKV0D!+fjZXi>x)P8g3=PX^(K)2A-%RAnBh75;_HdwXWN7DE(l^npy&-DQsFwF>L~I{vT7 z6qa0Ho$IUf8DE`0;LHr8%9McA8b~#QCY;a_byn_emO~1V%I`k!>&V<~v{xMmnko2x zHSrJ>DsNw1-?UkNM4SCV+-CfVOq7zco;TO?=Bu7J6)TDL0ln@YD03SS)DebmW7eSQ z{Xnp$T~sf0!$#{Drt8^#f#{zkAQg&I$W9w)AE<^PTfssrSm-IiLO&qQQN}h}F(Bc+ zv}FruI0tlcw=Oh&99lGgg3N0XLVF1W{&CPGlrtru2asthYtdYb=8G0hM0HY9u&xzE zN{80B4VqBJL2gA4!7&~ zny)%&*6KdS9z3$g!%H6ojW&iHsBPoj2Xn}3pnCIN^A|F&Bpt95>4yo3CD9_|Jmc&G zoGHZ@G8ZymgiM~zbn67WQx$|~fm#a!mJw{d?rpz^kZHdIfc`eks$EUP^nxLuelK%S-9*+eSTxyc@Vxx3m`Vc=$4liE#= zi9mKw1fom1HqeGz`H*LY3o#R(#+r{HlT6l0bDcC_bkdaEg9#Vw3JxW?3!j@G|iF>cWo64_6A}Np=ES% z+&W=39Cqxa=@+`;(DOaBi?5mulb{-EQx&ZNRC z!fQo%y(q#9%S4`;;J&|Aj}{PA2Qc=zN!{P1=u~9x+R@b)F_up+VwPFn5(iG}7rP&? z_hkXaQgo&3t#rNTr0YFA=ho3Q%1E#p24cEF4QgPci@I%Gj{S7*ec0uZz0_SlS#8BI zrMSpxg@BJ(ZC%%uWnEdGabg4N>@c=oK{g_YF$~B?%{hch)>H8+cEKwN zU?NWTt|O_cQwEZrR=9g#_x(~|pB8BAm1VuMJmZz+VZ3hUUYimG8G^)Kkj+WZt(C}) zT8?98-5<=udS!uCMCXrxZ4XIHmD38c{eCH#|A|-Rpj>^PtIzW(eVz{kwilkg@CI62 z0U2DNSyZr6rf4fXElvmQHOqtAr+@`jbj*D5VHJJhb>a2j!fR@6NdsY|3JBYPTB$>E zoq;o*n9s)RwXkX>O?}6!Co?IZI1qc@b=-d=*i`bRI4#BLpHiHrnQg@pkY(>ovIfnw zLSvi5#^`AOlZlue4L^MNLh5QE=P6DPD8#;wt?StOoMY?5198?IIEeuF5M9}5gYc=) z>e#wXLTblOuyHB(p4#}zQ=1eK{_p@>I2LEOvk3N~6D+35BG^T+{}RE57OzDdcJL%j7EMCerz+!lQ{D+%R5k}$D2==&}DM(k*_A1(bO40Vic%`Pj zS2sxS4kC3xRq4<>w@nL0jbkUB_#HlW@N3)x@pDZf2MZTbJnRXY%{g@0WWk zvO4QZTUlu<&q!N&m`yA9F_;b7-~^d%LTlV0yDR!e&C8)m?ww6JPty?}@cq{;*|jb1u4&SPf5d&uOx(Dh^%`cQL~qo@Qr zpT(LFAk*A=A#)+~MaV2YiU@5mkvhm|39Q=Uc$h_^l-$Q$^B9pMt2Qqp0 z@JhTkv{y+NG8ZymgG}p5rAmTrvVn{u5F7goj5n1!Dco3R*%n5%P zXI(Sip{aW>X;=|{A!(YqEz(@1`6AM6+FiL1*m?~R9}OaqfOKZ{O6l8y2vENizR=BH z{k_}iY7UZPe0;g=QPzdua)?es<^x}8=D5V!CCcp>+b*~5tK7Dh z(Yc|3MBPBT4QMSB(8h*)_yJKl1WomaW!N+e|&+-+Kcm-yUlHqSts6wfMUoD3wd#o-=kD zZ{B|^`>N6IX8e_ty>hajl9T;|^GWN*-q;{}Cy;GU$esmSVWvK~8y~P7_+@t;+#G3l zCFsgw(@fq5*#F+Ki=k#PpXLU7JDVQlO;7X1n~OJJ#hY6f$rc1Sv4JEB1WknK-m#Eq z%R^!imJ8hmXI}m8G!6am17(oO9yDm@VYA#N&Tk8+F|Krzm2UEsbdw(t=NOZHs{*a{ z0ph(vY9C;Nf|Zc09hzwo?>K@aE_AJ6KQ-|ECq;=0sb2p{d5AY3sgfvV<%F%Au&3mN z{Q#M>ZKb!;z_BaHs06LYgfU}at<^>xl7cAilm&}l@Cq{bNb7iKO($aFH1@NQ>Gy@8 zZ;qhCoU1MP|8-mNzbpjhpdw?>C&@8EW+ljp1$v3}(QD^8bU>lJ6aFQ3wR%){*XlcAXnDp9ZQyd z?JRL9?sMtaF;~@$*Hg-RN_o*!N^Oxmy?{~^kTC)>XoD_Db8EO&Ii%aNU4-vIQ?8D= zS?C>_DOhYzvpvrxbo`UkQnW1HcImb+(rxFQwPs6b$qi&WLiIgs8pUSuROUmvt;+8O z^EzwBMaxC5eWge-dLMJKFc!?6w9mpOmiqw+UwJc>5LY_pO2>RrI%eAn_T74*vL#5{ zJ3&=+53h|)OW$f9+Cf!*3$uR(XZ(I!`NEr$sPFPnk~*4^o+c0FeQ18&LCyEDy#>t$ z&DTIP)Y|4EP`N4yXFwgjL*KN{(TVDINV!$Hc~psuUXPSEi8p5Z&t0p;hJ-3-Ve>7> z?~a4-D{m$iT|S}Z6MB_T2+>R1c!RpXbc(hP;T6GH22)rRKa?D#a*-QSP`q6{uf2>> zaDE17DM?Z6wcsp9>*l#`p0B!jW^PdpE8tWIX;C3~FVEg+ldZMB9diop;JiK5>Tj3d z7jSBZe)>zXh>%jwYhysX?|uKqoV-HcSLpkbLf?Nd)^Zs+sWOO2fS?&PRtCY|HtrOX zN5@*dQ4<(%=)DF`NsK?3Gm^cWS3CC5SX(%Bol({q3|L~$iG!-!LCD@p z(2R@v?*aKw$TG*L2T&EG-KdbK9bA4e|H{|-*D2R)_Ik~J(Q7uMZbC(1i@mTjRG`j5 zP;q}{X}V9r2a!p)k$L@R#f0f2Y6y#XvY@-Zc>WDq^Y5B}|Ec+xdJ7|LU@dmzpXY7? ztWXP1rRm6iOic2N+=eXuj$8NwS!SWnkS$TlUio_#n_@Yhc^e^`xgfhB`vl1TKu_9c zCpJRZs5cPf3RQ9gZgb<>8<%-u8U#i;)jqmGWLd)Z3U{mW&tKsE{3JY?$Bvf-h}?L8v?-g!o^e7Sf*`s6vn z;%rKmewql3_c8l51|`*Ey`ZfZw5PnFJ*+5|q9ipZ*cjVhXJ4Sktgw~24Xlc-!8-|QHf-bLnhGG$Mb4`fE}X({4z7ME%sMJ5(O)uksbJ?R;G(!*3b zOh-X&P-P0p-1e%7ED$Wc%tUF&%0e|Rcza>B3tsWzGw<<5?|^0G{rmeo8@}GZ*?gr^ z6W8S@TzO7O$=2ms?A2JML+kjfVflV5iK8l#13Qm!$I_Du>!af5Mz}&52J)`X14_ z=Kz|!B%at7dS4*=%A8>s%htPWy-%_A{s5e%)09pV6sv)t?G8aPX!{47^k#glk#M)v z-_~xgUr6@^h7aacO>`4GQ6YLjyJfP4%!SNnAoF2?NSfJbnlOe>khX2mWHKN*w?dw% z$2@|!8<*lD`rGpG1+SvP@421I8pNsiN`c7tcl3qVh1VzG^#@E^Ytz(Sy4|dRLFKb0y|e==c@uc zd)tO|s$e7=2%*95On~UatMnLE=_oSw7Bcrtz-!19iVuITlAGmjwmWT_z26`D_1vk& zav^ge^F_!Uh>i9HK-1nqMr=?`2#WXGBhxVt7!l%9%Du;K{cSD!%9$nn(=@A*k;Un> zJ@bKSmUP+Xmu>zjw)r1Svsm0(dWAU*L40$l+7N1Kr8{=yav*^|E(I@iGuTMwdeT`hObXj45D-7^OVSqY|51Jju78S&#Kz8gvV~9}I*7?9R z`wN-3Zz+5!R}P)L>pdTPCTW`5i4LI$rdhGF{#MrC%2WPUe!!W;JuL@9nXDk2?XiFx zf|*Khje?F8L%bnVZ%?yvwHSiMP(EThg`#+-zV<^Ua&hM3%olNHbdFA=Lm&0O$`-2$ zsoiWVbMTS=-nbOH7t~6&M*fdMOKTZD1nRvmg$SkOzIWq~F97rIP3j1dW790%xo7TQWLI8Mn6=o)o{17sT;x0t(EXI$ubj!^v8LHI&Aw`y z#Z8qMVa~k{!kR*g6V%bR;+qrWfhVz_Aycktv$FS^y(5#&LNe_P`M?Pk}`AuE3U_osh4uIv{&rH^qn(>t=M~nyi=g1l=BoI zzt5TWCo+-AT-P|e#@QE*vnV43_p^yr0#Qe(Yy?t}Jf#g82Rf8~LGxzj0m-FYv9wDO zE$@q_xhD~)pY~O4_v3@ULX$||`n;D0v^1bsXh39LhdIGORFE-tbrv@uH;q!6Ne=vh z?Xh0>IzjWoS6x6+J|%l$1WTsNS3)D0|2fV|D*Bpc z*EIX0X_l#%a7>t3J4lHR&9@5K1`D=HV;ph;VY%ne^Q#d-EXDl81;in|2d?L7oOxdZ z`pTJJ5Eo}I&U_JPZkxAOJAsG(+OZD$te{q;-MXih&FFf#`koW7BM253oVOd}05Id7oN`y$X+XgV3M%gMT&yy|k&Dyq!FfL{9k3)Ueb z6e@F?i5Zmx33_qS+jfK8CtA5ueq!Oq@9tSFY?gbB`)M-JPb%xb@um>VdZAt~)GvCW zu6yXnRtQ3Rf*3ip+9$Y1#i^whJ`_9h6L9L)p|&Kx2hU;=$6(}QXKA!p?jJV4fpf3q zURu!7f?lKrm5rLuTA=hjd)9(sPpN`gOtiL`#E1S)cJulTEhu--0bgNG$H%?b*^MTS_kI40UvR+SK^m;-qhD0~OZL1(`3{mEU#GEoS>Lv&3ao@&TzVUkU2F`Nj z^~6$3ej00q6rE5`TR9(NPQ_TM?JKqYMXBw5jNUpYxaeLK zM{@lYoYxCCt)zYYQfH(DCG%-+JuG+^n_s($JS<|ZoNMKL(aISzd^+yI22w$CG|0&l zI^|Szwj2k#iQcez%X^R)E*H8&oPvV!PMk(zfh^@TImixQI1wp$nGcrv;8o@W9DyyT zK`FaoubDx7v4T-Wla5ZMfgm zpiI`~rd@8@7rAN0jj&0B((49-V?v5mDBg-jMCExDoVPwu-WE=|=GkLT{P+!HE-XxO zE$iU1PQUxVVPBKGcps`4G8ZzRfXs(G{f1Fy8wnvB?Z2D@GA+O|3zsrI>DZj>7recL z=JifL)rgNyKk+?$K~+w}>)|;!#XOcHVL1|>;YfHGubZQqkpWs&kbFCZhC}N%bXF^) z9_H5@twq1^dhPf6_to(|OGpSK1yAGG2k;upL9`r1&v6hvj92QllV<}@-7}_XLM0BM ztznHZq8*=yZ{s!ok}yQf?@6}K;YEswoiz{p{dxFXj7d1kx{a>e=reAk4+GXJGY;Gd z)_i{l9neA;f@|aARE_m?g1uUDy}K7a2$q}(4PQABE3z-VF1-Fzcopf|Ms2`B38Gw} z(NL&UyOgdms+~=+*Svued!Ow)!6uUzi#Tl{_TxEW9D!x|8#q* zX-^{M4J!#!;*6rpQ zx0{FYTB>*pL*UX9q@_UiNU#v19J*;7^Y{9N?p}1RBp0!>e99Elh;&Il@1k=&g~5?x z<)f^8lxO6lJd9VStu>bhL&88P62dv5;_QQlm5PV)dXHbPD#W30tq;E!SVJ$4UidV; z-Z%Vy%K+pki(ePN{!{!)t}TW)=r{(5wgDLhff`S@T845v7q4;k0xPBw?@!@-zjnH2 zIZbf#``Axor)^nn2A_pwjHkTS1{?wtc_<@Fv#)>n{2} z5W6FBVA+d~&LLR8Pq5zrE68+Ear!^@t~IxD-`B2)0G}e6-AJ;%|0P_g(|so!O-{x0IO11C6KPYGI8}-NlqxZ!W~D@sl`1G@hw6=> z6PvYOI;}@H;`{DaE*IY6h>N3r4cIj0lB}XIlOKvTc@$Uw&z+Np3V#o7OIw^|yrpuE}LDw@+n zH$8N};h}p5oV*}QalqCBRLLMh5jHR05iR^!^Wj)y@6S!!rGAT1(d(@y(GpY0>?~|1 zKh!P}-e9vZCr&lQR73oR8sZ6T7AA3bgx0)*b}7(gO^{98tFkH{AdT{Ze79x)Bl&(W z>WtFW?b@(b0!c=I@M#Tek9XSJhBbGcB=017e}&|I0+}SKqTHZ6FQBn9)UFJ@Yo)9` z>f(oxDGyd!{o%K1qhjrArDahRJ~2#*@UiCiTVM-n_*`k{O8cgjHa21QG+5CXw5ULC zw!+%7qHrPh1M;K1pni6!{Yc%$h4zl4Mv2#z)=LS-5j=kub^D5%LA*?8PH6rLG+);D zmP%!zVR%~%LESslO%vFvo7+}+Ibe9p3zp9!iXQ=MpNsH+0c(l=Wq8YA=G2mL7C)4a z4R7BIC*xvy{e?ytqZcAN>#mac5So57H!XNZC(Y=j--%9o0-9;W!WdB25t8JkKwUNh z%Sg$U&Fg^>!n}-kUr}E!x_9&BQtTQ+NGReKZh0CupP8GtOKqq+&!u)QweMPLrMG2> zaXW1VluV#fRoGVQ4VSH;99wGh5kce^-UFv$iL17c(1|fg@U)}nYjN8gF*A{7Cem+Y zB0VuV>(V2T9eP_0v~-4sn?k{iflO{k(#oCzXZ#>YNc*a(AXE!4!}EO}I3M%3-+r8y z=Cea)cF4S`Lk4B#x~KzI?w}*~Ge;7`Cc1b}B(ejwr9;Q}C|mo7E`BBZQpFRRhM}h8 zdEk7kN%*$b`XH$$I43yY1J3BmOH%>LGAt`xA*>~A=vaF3mHCidi10II?8nKe7u+eT z7_ue(>(4ptB3h!Hc1L+el<*Cl=t*;O&dK?v$=Sl3WpfBxH_);rw5kX^wDFs)b=?k# z;6Em(-FIx43-5uGlJUyb(uek!k@+-(3gKf%**9s7GaadHSK@MtYYppfzS^b!FPyE97@0@ax9dMc=`&A#5s7``X z%2|W+3H#XX+$>y3rh9C<$KK=~^IptFHsIz6T1lam)nU`6X_YQS2b`UGvAc7V@XPx7 zUucS`=5=nGP$m|m)7YR_5=@xpcXNI>-}T*$EHztiAYDfxQxQl^hOJv^Yv!`>VPyV% zMH$HST`oveq+ETS#u65)_)cVMe%y8DUvvI7-|^QR9fFG)L##vYzGgz(3W9OE%TiM` zjw17CB8YJ8ySPIHiH3Z!w8jxbrF5S5;FXz)l2fxcHG6N;>N>N1rou&dm4B%vv~G=mw>*g0d~p z3OS_qH8y1N?NAoNKxW)S<~3dZ7MaZD8Xj+|CXSJ(iD_SGXG#2^hbJ;8GT(vBC6-#l z8B}f5I;<QX_Y7pNryHph+CTU9@#26~80jf?FeQ&I6R2FQ&~EzU#c3;#^k zGLbov`6gtNl&)nlz$J#ppllEub)f7~Eta%;plk5MGHpL6dkt>3e3pm)7nuc%`E_Oz z;wa`6K|Kqae|ogwI5{QhAgU=&@UKpFD%$%T^6ZEc}pjBeAC=A6m1;rq!TU)>~#gQfI zcA$RYL%n{-7&aDKztCQ#wxpIXWO6z?Nys~q$;wk~FvSLM5*u)-omy=p)}4m&WPzGJ zfw)+6Uo`m`JzFk(pPn6EMmxw<3BOu4jZK(Boh_j2|A2=w+2Cq`*_jf(byLE@;V%}jqB z+;tmyDUOuWr#XF^Z}MrTmsPSTEWA`usRpq|h0>R@^&Z9Jm_qM=(%7Gd<~2O%W@us- z{u-LdnIy%|Q?);?xV}{zAjVYaO@-dO6nZX8v_)6oIy(LqN(d?yS`JbMmu$z{ip(#3 zUkBu$KhYaxmY~0!U>Xq~D0W(x^$Y8)>ztW$X8y{|e7O&0^JVSP1ZY(LX>^2;(!rzD zVcpckqf72X%64B-i}BYnMWk@3(rF=kuTZwi(}gl!DDQHi@QT#M3TUYdXoimO=LV&> zt@V{F>oG;`6Ufw^Motm-ub?0sCD!hod&qokl0Hr%x!rNagC=D=Dcj$mY+s(FHJ0qQ zFm!AJTDOGYPSA+Zn}w|hPb^R17564-LH}!#s;4p{orl*~h}?`hN#`W}jY;}4Ub8li z_y{T4R#0mS?IZfD%eHE*_W{qWFC z$I5i9obFh88LzlC@@fn4)(n)mLzAjt)w+A@*5g=Sf`8^>{y1M_pIMUpkHd`Ahl+tt z!|UUp>g_&kR(#f|%o>&7s8M+tud+&Y7Xnu-pj{QJ20>9Zr4OcXsdoO84%|cx}kBF)lDNc|f~#h_(XR+X)^CGA*pihp`yj!sw){*vZ<4xM4Jp2j$NKK#Lc18h=Er|EQ>{)*G|^)GCx z%Z6^?vNX`8Hb`F$dSa2qTcviWYy#aPg(7r6t92u5Ua;@GuRy`N5v}+?D6-;!^5==@$=3;i1S~wqb zPPdl0QndI4>;&v@0QQNPPogAeFA&m30PkYMbAyn%HCtC|Wjl7hiHqEaX1U;A_R0t> z`%8X^k!}U$G$H>B0lXz}%7v#~_&4OjPatz!Qz+12Lru`2291lr+PU;~Ls||B4dcH|3?- zBF7S0;WciImmX}#ylbTCw zD_HXQlyZS)j<6uR%EmqT*nG_k-6xUqLVHDOk{DmYU~v9|nMNjfL#dnPGbVODa`A_>~CLS5Dl#FA>EYwOP|8~z|u?@!YBtgE=$ak=1M zW>rj!f@fBeJ}!#6HNR1moWh1FZ1@df!xPAqy7p#ULLXUYnr(#`jWI&p1Et}5;O_DV znGbqm{6afykvSnKOBc}%yp#aNjUd<+Xss24YQs3T&pv{t=mqyAxt3&njcwpEEMgxG6({{PA4BsS zXUmk61DYJrn>Zj1#H2L998tYU4%sjv7mi%HEsH+yAN?GfciGv|N3kQm)l7^lGKZ}s z(LCrZWcp(r(YK)~S!9ZDr}*|w;@jG)5}JeJkPOkr5G@*zVb$J3)&too1DgK}wf_m4 zwqHrAY^Y!KY(Wy^kkgE3Pe}Z3jAuEb45v|a8b$vpqo@h@Uh4{y%L2L~L$gfaDi!N0 zrMKs^dIw(rcgOq@uladzxgDh?zRoEg8jR!rch-^{kNab8jiMv;UT5$A?A?D;@BX$) z$3z3#xPfXc(3W07b>YyJWUJ4|8jac}d@xFd_tkt({6!5Jx~iIcoc8~GeCfRXf0D^; zDxFQG?`kUbSZ&?b0_i0|m#&bZ2-emWEmoBSft~}I^y$U^X=sYN9&-G4w=y2|ydsf@v7Bz6`w^)WPWzM5{XF;AWI)cK}Ur*B1;kPgj9@}}qt zjlF_1TM_HqvOS-?IglwAzPry_*(HILwS0A{6%8sRe4gCB9KNRz6>^-O>p=@O1tk zduNiI+LCnZ5xH4-?apkXoc|D>ZKbZHtHS|p9!k=F3mUZOF1%Xtt^d9>Wm=R#1YO5V zl*$zXtH8inu*NKN@+oQRMQ+A0(O>8Y&Jp?H4?-=4*z;-q>?5&hD7xQt?l+yk@uu?! z&OL9|yh(xiM%2_%p)FfbvQT&(!sWCwZ{n(tCD4_ksf=G>n$Cq8J)Z~Xdu%@&yul?K zT=E;>k{?L36e_I@1D&OV-~s2OIsoY)gjnroz|@B{?V>k}Ci4ZafDn|J=+kdNVS#?# zAN1G~=n-iu+BOJngV1jngnl5+$}CJHVTBTiV};PdV5@uQK`#AV)$~ibN#{GRnpdhO zzw!9~k)|SA3cEc`nve9e$7d^ZEAutVbnKeL5Ju+;!Zjh07E~X7lu*)s%J0s6(c8~A z^J+iKjO3qAAeLa0w@L3gMe_$-ukXwQC$(*N-*)#G+1;fMj+6mw_5{IL5c!t4VkK~8 zxSU$gvRvezGU*y8h!FW>(p1tUEAl)i&=1~-eOIO$+oq9h8p(@jBo(z;tpf(;;nC9t zb#;MIXBxAFcs->|eYfEKRhfFBs{svK_`_|Gm_iYXPutG^AfVy9+rUg|51M<>eAS@Y zxvnYH;4s92SnJS;DwJj9X4Q;Ny*XihkGub?G~>coj6jTs#6OBADiu|J-kXyj44U7I zrj*$2>~3dY)z0?Gb4=>MngwL=fQra)1O}=NcPyu{mxnU%rI6v3qRDtr4nCAg#VC{X zd7Pm8Me~n#)-(3qWZz9*bT`qgZO$s-g^qkc8&J6;w3)@0U@3B{W~$sIc;Q9=k?uET z3ORo&QxF|h%hP;7kD%R=aASftCg??&pvppxYJwK?!`9Bw%ouv6x5_i;I%R9Wt4#6t zC)WQ~rUc^Wa@JjwGsvIT%|4WkErGk8-RE|XCn~l4cb@) zmNM!vHXP^rS$!WQuTPqI(Q=_HuxMfAFIAKLh|uN#D);h_s)?Mtq1_Gbs~TD_!Idik z7gmr-3@OKp&5Fet=iqXRJ912tH=dl}Me$OuNz+{AV?FDpp-$zAbiKG+HUE%i6v9n6 z*mQ#z(G4m$X~qG=ae#~iNozbn!>!j&y^K>wP1T#J^Ka7RE3+o^k+$-WG?kQ7QRQh3 z?L!tl-vPQiK=)Sybbrv#n#9z`1xBm^(qcee&cN8(aIbU5Df6uQy?)j%dgZ1mTJUo} z>sm@U(euo+KS0v{Q8Xn)_ZDbxfnKx)8fa#N8P*^Qm#>_H|Qt@q?ZP%l>kX6k5Y7uvx4Q@ zwKOkuWo;{B${%65mSUbN%+F#-+x@lecfk@W(;h(g0QwsP=);1w6dWxBbc!D7)(c{d zgi$nCQa|#ppDS2!p(veC#nJ2SlmFe z*0DPF0V@lGG(~7j5wxYW)oG4??)dTpWtJ;^1aV~gc(&q}sqRJXS@|iC4Xdczg1ara zzhS|BxRkb8ykV~ps~sm9?NCdL<7?Qms9|RpzqbX8`M!So-ut5GM=7;53YE;~Eq>1j zs2mYYxCOff`x}D&!A&O0a$93US8rKJ;F2DF$1B*r)rJr`)QdFP2#o;;PtRpSvW z#}~b_1PN22r)38|GL@q2JI%h+{7>C!qSv~{EYPP0h}(cxhQsJiZS_HgPQgzOz20^s z<<%Ho4w1mm`kJE0)0d~sst?pxaos7rJB9aGQh5JA>T4xB9*yF#3DU-dwvxaC%N%Z1 z*XjCtTd)3}tNrg$m5o?Fc1y<_QlogwKY3k0Y(@83b)QxLr_QRC>O|%ayv#tNPe^M7 zg{}EqZs=!y5VxPN9cR^RtlV-qmHyGIM|hwxKCQk!V#If6+JyN{nEwsJ{KEw{W3HO3 z!RTE;1~v#R70k6tNV={#E7;pFXYAd-|E<7^QGECyl%k|?J`rs6K!FX~*@HWK@KxD^ zXa!^C;mjWkghxVUDloC8by{4{B|`j2nO90F%YR7H@1rX7A=Pw$)|KV~Wm?hPtKhu~ z{*6`e4~{g2SIlsPIjVqkDRA_?z;#p}vpC}ECie!X^KFTAJw-`HzYL|p_D+3&-B8N8 zQ27}^o1M@GmJn`4n$xkH1De|8M5Ns(l;&`H}(3LqpF1I2e?6{B$|o7 zRIil2?GD@S@EdlAhxKaHDX}>e3k6{>P=yH^3TEW!y`D1^#)WRySK;^9Hh*-!#lJim z4?nJ|`O3~$4Q0=ydnSF+OxncMs2$wvQ9xo%Xr*FT_ScR-Ier3m2^pG$=1Pq z83?w6TTca;O4p$3IZuqAcq!#(4AUF8{u&*d#Y=v!cUd#kiak%6=f_Vgwh6qO!22o! zuMEXD%peLD5X%X{DbSd@dh3Pii5~Y&nRr{7em(A2!akF@m4Ymo<#}(wA6X39rXp=B z(yvgFesB`Sr0J~&w4-oJs|B)-1?0n4XDPFu=w{!PNw-fde8ForB6In&vK6;vrzeJr z-hTuBy_=0h+R24Gx$s5Fg~^pyV})q(7WbQQ&^;krn5JoKJx?lA?m6hM261bIf4+EO zM-C!-+GFnr=1fZ~TbWy#FH$D^U>~JJ_Y@GV3+f~Ucakp48_pAC>^EiVZLhpsWd^dP z%EvK9S05zdKQUjPgZ7Ll>V%l zB24mGGqo5VsrmLa!_fVj`Rx@;nmBD`Ze{+4G9SLB6qPo41dPMwC#@C8nTJ2Oi(>0D z+u0sh`JP^{R8m1E{Qw%NMw&<1e^al2^th6;t@7I{{~K2M$Mrg^NQffS7Cb<{-?YOQY2O#hj+d)h?qdto<}Cd zs5)((dhmjmf_LK8q+IZ-UW@2wKg=3@WFbB+`S5{BRou&_rfh1;Z%|WyaCgbtimvED zVGU%~1&uU7U5>{sCRNW(s`$RV{p$|tI?9uSgFY)Mk{#ZCq^Bv9PAd~BY)`6tQvHod z^(Pn6%HAjiYV-z@5fEJ}VD=U>np>W`h~mBH+jKQujRP^ikO57CL+q7c1##XkqU|Dj zm5YdVku^I|^@lS1Bxq3;l0&$)l55IYW!`qm=hbjEbx!-}W}PyNn(Fhyg6}Ic{=F?i zN~b-3?(y?i#?K!VO+t$rgJ6{vAmVns)Se(wEWFI3^+YPuf24WaMif^g_BloH)8Hq} zdaxFrH)uYv$UU4)TbWy#uTf^HI5M#S#{s5asE~6hNb#gneEB%5%sVUFzr4wIBl&!; z!on6v{7UPsB<=X69l!Ld_@z1|N|%7P$U$-mM6?Ext!8bN$j`O2bjPfK^o}d~w=xyO z^kdL8reG=spH?&NzB0eJvq+`z#u05C(Qn|0eo!>mG7(+^wOKhhegREM!53Mb-qU5A zk|y7KuaXzK;)++Lq)%xYvqfQ#r%CgE$mk!^bWGZl=AJZPG-=MNeF|5oL=!}6oQ5Uzo$>7Y`7NRuMiR0~}@obV&kr2B#0{BLP$@j%_m+{*j~Wj<^f z>QfVk9*|9{$2mozRYxEWMXhA*OmGWcN?i0dc_=P;%`ET9@oDkna6SUF?OCPtkz5aq;f6(OSusY^IP+0;Z>X2p?3Q{2(O(M^2hT}lteN5DhqvMcGXq`y%~f1u1lM9bR*YhfU(95u5qP|Z4<;bb{yLCAX?O}yZhXDsZ> zlAnknI$nN?KJQWX`I_m)W7o`GGhb9QdrWpSgSCnsJ_Lib+F^{@(51H8&ehC&@Gq6? z26!*YpEXm|)3dzvQT74<+UB5b4tkL}2uZRpcc67Rgfa}OtqI;LX4isC<{4$;J@}W% zg|1@x(#j|Ni$acu)?fN4n{4No?fkM|$uIjsH>*O6F$>tt0@BH$wr;RWo0UtYQO+t; zZyIXFFXb9y=*av2bRbY+j(8?w=z%%&Fh^}=Ze_kknN1^BL5AM=pu$gvtl41A(Tt06 zZ+1$VauInXUqw^s%LYiwVRbLhtC^1|(|vD%_6F!h8z7%Ff-^w+K#Ub+DiDd#x?g7#)_&H}Hx_H_XYvu#6gJ9jTgAF@)5$vGasw>7J z%0rp66=0YQh$oy!~Q?n&M31NY41 zzhT$RT{B-(Gv^}gr6XXY14FVHV)=k0WXoIay`6*V;Xjm-zt&8Br|x}Irjq8DtBISX zmwX=U;Jh-8q-<#IhSvTDwDt$e(yFwOeaNwaUSDrb~ zb+i7Sym^+~W%`8=q?FD z8=%8{cf$ijf1_Qx@|#QbKQ$8zI(uQur%4mb{i=!O-(~|0B$EHjb#trpe_EZLqsKA_ z(5Aa^4iukdoJt zsq?<&Ais$-#87r$yZhP~^|jR7Y{dmE#{fYyXmSupT51j~jrbS1^jMQ)_CC2oo2!CE z6^LOCrq3QLxOG2uLQ%iq4UqerIOR&&WKWEbvZ<0{sc!tj6l{-3sgP2U#p{f8O7sV_v`mJy4T_uoCxV7_zz35V2XI&)6NI) zEslFO-LvVdX4A!07Y+u`dIaW*LQ5@xcs${v&dKMlp?*QXS5B`uhzQN~V>abNN}TFX zOJv~t=a%n@43s2WnOm8^q0EP?X=GrXbHHeJYeZ6hYx9f>rxdupFNJxlB?aH*_jbTPEGFrGG4cOYXDGKFj>dS?2NXw=O~P1vL-s z$?;G$O0A$R8YW8daVm9J{pNcYdLy1(Io5ay!4FqG7Lq_c9)rEK`<0a32Bd93dXWK% zb>$>yKsy$_vkPQ8f*maCbmrPmg$3RhCtc`@IL%c*4MR2XP|wE zQ=MF*I6iG}r1z!yZ45ouR|B5K*{0|~W5?{TE$heNf2P&!T;HM+KQ zzNB~$TKcOvAWJ3i z91zU>`C5GVgJ9kE{P%X>3i4DKD_=t3bnRv;eBN>5xTU)IDuheTXWrtqTqxnIH}A&DsVM5q4!p7{H?8sWMj z+Z(d|D#$kWqj-7+K3IfOA|a>=&~)wCi&Hy?WVtI&d;h_|cS#2rl*@-7g2@@xM5H_o z`@r{^Ec^|#eR!(ad0%Yy#pV|-Ha}=~YgDOT6ErnI8>e#yM?SCFwY!r2quF($O@7$qhhHH-{GgiJL0_>x zfY%U^Dh+Z)hlbc?bSrkonnagU?me!Ft56n4D*i>BBIIHv{CSh;1L8CVB5`s%NP=cpmUxNG<_VYe1a^p%YFnn6>(e+;6%RyvXgN3%}bQzKJsgKQl~^ zH{+3(kuPp*_3dTsUJ~sk(JPijVk(P@0;(s-%40t?1qMmiVwz)}a4^uN=%w7OoFZ4B zv{_it7jY7obP_Dj6Xzq9)5G>7nf*xSHy+9SVCL*potPMq-;#xgLmoc+!cu5zo28w| zVxvp3dw#&Ye*GlF_$p33>+5Ph;eY>%UBWG@R!geRT z$el2x@ua$dN1Gru2PE|dWA@-WXDer54Ri$b^9}0|zZK6boh=8Eew;s*h)9dt(@14{ zUz^{(xh!Qv1UE$RRS?0x7Ev1sOUOVf4ya>Ipl;sFoHo3jRHoi=&GX+Ljk1?7k4BaJ zm^e*dtIVA|v6ClWmORmx=BQ}EQH~=gI)wOyW>xB(2So5(&D5KBls9Gam5?Zw(b+NIpC znRt;a%48$rkC!V-goj{YG zo5`JT*G#_96&F0aX!)p_%90`Z7UcURW!_)WepjZ(8-itbv%8ypNjF;#DqIA7xI!S!s6!dtQ5{22Grp)`7&F{)|blS??%6ySBnas9y+dECPjk#h=XSI9UK0PROu3Y+HIp?zZkj5Q&d%|?ZuY*({kt-g zRJT)aJM~`V)YBEKdk~l(s7(xm#tk96V!9jYI6G(FV&n1~JolP1%}RV;O@x(5kjvAQ z`9L>oO1_o3mH8TFW;I=w4!x6t&K{N>}X+0p-!!&T_I`#JCkml`n zHs9|m-->3Ce*)!I^k9#Ly>tb1#F=hoZe_kknVQ8a6^Er_AZ-P-i3?U;QCN7CJoWHI z{U+>y|C)U!h3RuSTZBW7&$Cc`dcSDOzl&xBXKoYFHUa&H3Fu)sNodpb)j`)hR<`WW zLOVnyYIF2OPu45*RXB-}OMdVVGTs8QqsX%=DVF;15mZ_30%#b~dF_G;)i zRzr`sxiz!TVvuVzknC@6J_A$g+WNq8(lg}mX1%iuqhzwrNbX}11Wf>4uxTEQ;ae6MjC)lgKZ;;ccmB`dRjVPWb*ar*? z>bW<(d&B!18{UWY%4+WA;Kfr^kkKd9J`H?Hv)RH+_Gjz$T1R|bKm0Q?N!be}sywa0 zJ}|4A@;2peQ|@n=av!g+Z4Qb`FbWqCp$4IS!5W;=wX8e?rT&jzZ!n17th#iizKXKz zhhF_~AtfW@v+AqU-3#h>iafb6ZAajC1pbC2@L|C!5(kQac}$Q@f{fxYZ8}nOMLlPE z@b`ZAMuEkv@6j;r0~&VF71Wbap0*5rfUaQZyTI-O`x^!J2bPB}4FgAkAP*340(GST zEvJgLHOv!%EN`V$@MbB^s|a~^`Im#&mEYc^J#AEd;H9Y8CK7ET(XSAR9&dd`ajt?8 zeq`m_KxnxVvSI7FvelEmUcVXn@YeduHBOOo#+SD+Dp>M~X`v74HMd^3UjMiBS`U(S zuM_4QBgImnwKiZP&7&i(dHQxEj}ZT)pnuV8qEH;xh-cX#?7lW zMJj1Y(}5czNTUW-eL-RlC-syw!Q207eQ!UJ!3$k;`fUp6tgFy7#cuSasYG5P(mzpA|?Na zdcAf)4Kw?&0K0h>%?y89fxT~d_@ltm@o;7fb_@1@Nw9v*gdPbo(m=W>H0uVHXK^0p z?B~`VU1R!a}GF`&0x zAWarT?FcIdxyvjp^`v0wCdmx*J(ToYM{KD6;ZQo(u%=#=pY>ezAxoi(?f0ttz3PkJ ztFB7br65Q>EDwtj>gWo=;w>9$i*xwTxN|}kyx_Ivk|up!E`=0Bf8tB>2P_Y!u^A7W z@$e$X!$I8?c7ceIAhR~e#udtuHEK0!@VPrp+{b@j>vF|Qkq`cg8)0F=c;21nfi)6i z(arzd{LkOue?Hvh)<%gI1*W5eH0%(p4eE&Eoh=a0@p|L^9ot{WQoG*e9!u5_H z+_C#Izh7Se-TP`vd?B0(>2bM{r`ZSdeue!GII|;bf4`jBFK1r#a;ElHT!%o7d0>1c zp=mOd8onsJr=P$m{YRQN-?T}&`UsWHqkK8ZI0}YFK1-SpJsQW@Z&3Fe)Zci6`UB5B zn{ksS5G9T`Z8@O21Y}v_g-nW_c+^s&oTmI!6h=PC1ng^?HC ztK9#atK3(+k$#}eA*f3XVWks$DDWqfy9?WcWS0wubFl*20sQ(ETT#- z<#|OD%YAL;zqN^>Z2P6!eyR4VmuitA;ntz(2$1R(S|x`>RvDub`3c?;Uy8ibQT|#s z^*vSin>Yg*KX^x2)Lg_$=(Fl3mit7(Kg8*p`$f!t5%ViAVtz7hdiK&v0o6zln*y0r zfujx<<{El#4|G?Y$13QGJ;CFPmtHwF%^9Dj&4+qg=RIxiY4b(Xrq1+YHX+p!MEppf zm{V(1+Q*siS%<1M2ApO%kzvw=S}l0vMGU^68I~Wz#r61 z^x1k}0Wn$yNjiK8y+AKXfn`W3C&FR)QtXa#Na8vm+YS!OhcX3CLWK2c%6y<^BHA7` z_o(@zQFC=!Q>+2D86dqR)ae6w3Rfv8mgj0_T&UctnIGw;-)g41#K#^;rKna(V ze3VTr9Hh>|Pn$Kd+%KGeY-l-ShcxYwre6tZ`oXlRq?y$waH|ed=YlF0fQu|xRueks zI>>ubr1qZI^i7oVRVXs#norW|HND^@qhUiW^dSo;dHv8~!2A6x%cBo;hDNb2jY7 z3pQwYw6)C#)HVs)>?5rYPdh-={hNPblJkx_YQu%47pu7*_{3BnV zoqR89_oDVii`t@0(#(O)C&*z33SaG@mY85?%sAE5BE3To{yK5``zH6BG);p)j+2$eJz@Y z%C_!p>)vlz_Z~*p&Q?cqAf!$MadU`169TzLPzJ6O(MNBJr5nbC|J2hfip4wvdp{g~ zq{*S`j&?<}`p_`?gYzfJzYD4;Qz^Tk?t=Oo1@&RkwuYUfD3s}Z01_0chXHrR$@Sov zoNa>nM&kCHXywZ7#nr+;Eb__6mRXVGX=V0){Lyz0uAwIH+snSa{KoC&VZpMkQb@+Z z>sug;D+HrLDTxa!4ezHOoc%gzj~wzW&E@^U`ah5!4>o8?V0YM zQ2*RBi6iY_50lc61=+_0 zA{kyg635vUliqmf{U%uCD}rUgPejVGkybhwMo+7-=bw2ih3;qG`ilN;#Z=Mlf!H31U-3Zvq;?J|W1+!p2TGU9gv8Z= z9o1`kZNpBg6K{{A?gX_2x6m3E-gs{)kI^a6)J1M@e;dci%>stD1B2W-BhRe)py`Y#`u9~z~fSiQl3c!e5iIxknGNOceXF; zY_+4YaKh3?AYK*(W&@0+L7ir6XFJrPshuqDC5WF`JAW{D{!u&QKctAQ z&aKW@sI&O=L8XJxIBKU2XqFY6Rx89QI8Ize<%sd+o1g}v>*`cv`gksbhzIDJ$zMHp zqL=*;d_M$#(L?Z(y%0->RW(3j22_~~)ZDyfuf3h%G`y)(Zo2H{dP+oMygk+a2Sguf zxhZ)0l_|-r}ic7j5?9;bhaE< zAxHVfo&Ttvr3i8$=JPt+@`JgPzp2wLVsC}^R_Ik*p;0|6&I!88F?SAw+Ob1vzN}QW zmZ!Et$QQYJQ8_x>D+b*(%lzC574zb0r93S&^d~tHf2cE@3vP98b-qZQbI^)n4pwJ7 zo}&$@L=&<#A4{7{o2S$%@7}$?sFrN3grQDD7{ZpMBg4-*! zy+SYY3YFfQx=kR=0n&Lwtx8~HTKDCBj#G2zf$zLgJN3eTwX+ph@(-_&h6G0ujc18d z?>}z&hVI0If*X3hq1Ug1UI+4$p$Jx%fFL!f*%Dgq8kmc9p0e>Bxu7@LfObyld(TiLs>WZV|m%?e5>=IAg)av~s=O2ZW(e@^2 zZ-QR632M=1^op?F9$_zEP^}Ia>{FG~*iYR!?<7U&MdCfV@S8MMSou?$N*PA+yiL#} z(&XG3OFLufRT)cNM-$`<%Pc@>O=#K~dT*t%ATphkrd_z)lBVMIaZ@qn!yKe8B@{EB z=6Zi@+>9u@q1_GbYZ_V&^tp0^=TZ=^1To8mRf(wNtn8<*n}?;H6ARL1pk!X2ZNBbC6lN`%_EVdtuz38#nXsvL`1k5AXm#jkVIe_}Y8bi$5x$EXV zbs}B(iaOOwp$|)~n-@_k{IoT#-!Gj0O`0rDxv83)s`(pK%^&o%Xq-`N1D1s#CIV5q z0wZ#>v9g@w2OYUdH(rXp6;8eqN+=qXA4}S!zhyHLeHK5{?h_FH=xH<3ch%fg^EayI z!#F-^tIs(U>huI@J)ou^{IA+)7$VksQn0sjmEHt<4Jo8V<!5M)6iPS9 zBek&gT5U!{J@;Z;&ptCCjFd_;%hLq=&NR^j@&`m1Uej%FE|5=GM~b%0o1DF7ok++ezeze+qw=VEsN|;g1R{ z$Yt+?_dfVH_Q4MeHZuCq#ZbH$$QlIEO9h-7M?P9&o;$DRd%FG&!3tgxY~i;Q;D2UV z_bi;4Pph!!oe$_C+xf7a55MAkcv!G)>8L~nI*kRAV?tFtatxO>FCj(Gy^P75XzTxM ziLbpU|tx#|fh?WZ3*8r_H zjHqJvvlUiv&#>2X3^g(HV@vF6>LtUTR$*Q4+L!(iY*N^+u)D(kPgU4jD~{1BDgnM}pl z{bMrKC{#=`^;zP4=zSaGo=o>-`YV&^52P6tNgM-K_QUuf2r;>VI(3`E+Ru1_^-}l_ zPUSE@Tq~U7{H1VWF%?019);||M>OKwUAWzazv3?ZfjUJzjCz5Zgdm*}D%QiLlx&qL zy`LL6`DUie+rW8^d@W`uUtXUUvZHi9?_u}@1E=v$TiR($uS#3eQm4{tFtQd9!z18# z1R407Qp!)fI_aR)sp*f&#u-t(KyweMr-piwa5d)9#@6 zy}aK+*rcKRJ?egs`oHxawbIC9hA>tUklGJ&eJ3b19anN=JrOnfCRn~F*lV=_qd;80 z)I^GXyhn9mCKYpensMQN4DcUbyI5YoPJD1-`7|yBMnUE0#p*xS{NjF(y5FPz%6rrw)KYCI=%}E0I2R7u-$%hLjriUoM*e zkG(6&ZD!}SD8K$6NEH1)0$m-Jmk|L=WPl2t#ynzXynoD5&K z&pzgcu1qaS?7oKP8k#2!%{uGostQ#kK(G#IJ_q11j?CV?9$jZ2AT!_h-RqyG#%E-T zN+h!T>k@hOaZUF%GBt~>kLLPlp7hadeNtm5n1;H$S2oDr1I%JjB+@ny>EjXKgX;hK z(Zq|~LMEfiM}@u`5s8w$EXZCTi;1q0={rNbkhzd~4l+m0ku)lF+*6Ch8&q=xMd^Y> zIgjK5{sftNyZ$AE`D^`)7EY1ZeKa2naIcY>D(j!Q{+Va}Gu`J%WPw?zf|w&z+X{py zw!TLvs2@e<-EDTCnKw?FN)lg?Y2+fL_&Q`hH8Xk5%r!Glnwce{JJt!s>jariAcZ?r z>tn-o%Qg=oQ!aWpI81JhDR-gC{FjSnM)@RX&B!zo|I3f&l@2JQ;0iEV0VZb!m~2j+ zN^gLn6U2id#2hfJ_QY+n9@4-QUdmm2%8tw%l3H=H@+kviDTM`Js5N+eHn~P73$Jx{ zt+QvXv%PQbwK}A71(`Gd%8TAX^_-G=Ql+OxaRKXG{oOWZO z->%cwxz$e117 z4xKgGE_7Evt8robJ~?G?E&NE3S1%|i?5`t&9z#>VL9@87@8s-`W z9(y&h{2QFOD`jS9OG{jK`3)HF3GlP;_mfDlUPZP{ zG(E)9K1OHWoSow3%k0!BQd~skRp5Lk<$w^^0c9Of&N`rkjcl~doeHwOn0MQov;}lT zqiF1%@B9K4J84!t!870xn1}8qw-}^o|UDn`SgY(3}S=hHC z(0ori=q!+-4LsPzJ*wuRq=U!kjQ0mu=rq^Q8_KRlpxw2pFUto)d|aIU9i57jOB=Mb zK__X0La`4m3TTr-_N<^_9FS#h+&1bm4{3vRSGzx0Ys(F7Q0&PDAC_vwf@-88FH1Xk zu03V1Hd?cD&CZi%C+3toG@+v~NY)9h_W)I&%q4cC*dcV<`{Mf7%{DK1OH&&u@oB3L zA#r7Vou>8~BZ|F^^R?Elwf2m)mS&Q+Vucr`xQT8$tri1D&N=MSKH<*UZR{zr(rpt+!V0yM+4MbipAq=6Jp$WbS7MHKFX ztRLfp{BE}1+acvvOi-e~nKl3UaS{eGmRIhyKj4Gt3Y}?tXX)B$*G_xRPHUYSm+rtl z9c0Y8CtosXZM8(1%=1v}!G6WO<3_QIl$$?JB`W-ZPIXnWM0?%fe5|ScHaJVkr9fB; zgtHU~Lndl;hdK5XuVD(&N!Nq2c#j&~yWnhC0 zfaSX%P|Eja>?^<$#g|eP7bhW$*Bw=-ns6bC*3=9nz(EUwABq{lnxcS zL2W4BEZxV^E%!b&)o+?QZBM!Tn5B+JrKl*rYL@zArO>xpPEq9*g|MO!ej^Iu=~=2; zE1DEA$NdVrF;w*lZ7alJPpgJ{Avs11vew zy0ff1%WvFSo(8NNr5F=L_qU>k0kze=tP}e{YvF^B0`@+|>$gLvQA+BEjm6D{h|8(V z@2;d+ilU_`I!RH4ZKTY?FkC7~+Zt3Z4C-!b+=BF&6gMt%U$&4JxuGbs-C*|dFSW=$ z@%na$%5y~0V`yH_QcQJQ%kNr#|EHGUky4_T0%gzyY0@D|ub?AIjfsvkzjFV#8W+6* zSoNfWUjSHV5Gt5PdY*Mwectm0HJt0$2+255wA@Y8Fp?9blgkLzJK;hFD^V|0yv<-Abp{ z6VQ`DM9Lpog!?SysFr%nVHy{`)7tU|*js$CWXP94tO_TZ<$tMOx{ftMVdiCHTQ;`e zu(3ToVY`MD!w$`wfJ}F&Tm@>a!jzbGJEqak3qD$jZ%HIXEz0K~w(Rg#34R%1A75Or z0b7h@t;B03{@+@O*~74+!Y~~m%_r391j?nMzsU`cvBdvGG~5B~tyoWq;`s?!p|aPK zp}cIuKCWK+HetzA*2Q&QTz})@`t*b~nOJB97-QWHsvW{Tc9F1;CbMEac8ARe5($d; z=!dI6EYq9h@LeKd#7G(VI)mzCtIgF}Cqr^s$Cq{dEbF+o&aHYvYf2!tUve-Jx{|QW zHfbJH8|FpsTW$QpHxv?*#Qd4L;#^ET{AKa=Kd_Epjnd3aUXyf9(%+b*KUi`jHr%8b zXc-ek8bYEFU?0L)Zx~Wn>%~;iOj+!M9ls}WL`@lN)gvJG}q8P zX=pNsHrEYI`o7M(L2lMzYg?yHnR*;J$-F`HUWcJw$Zv}tILJStsTQe!oZByg<}>T8 z#>#Y9nGPpqI*@7C)&r1p1JN|7Q6|KQnjwU(9wH8-B3QreerIflksvnmOdK3gTN;+uTSGLb zO;d?P@z=GzJTWxUlGe~%L-U-W=}I9nCKTD*^2=TLe)3E|$0*iH*+;O?s^1m472s5mVOrbDckb^%Vr($VP>@W6mMx+5 zEZ9`6xdAk(NQ5n{PT&gwJBw8v3o-^f`cp5`N zlUQ5s+Hz0Ya!tcGogH-c0%D9%Ssb{IK^RJQq*uZ&MIM!m+C^^E7^Y(bLC)?_aC4b+Q0em^H1GFH{H2{+i`y5{ zHp!@z)O-~*pQcZGYpN7a9a zW{|6XTsrsP-)_%Fd6_;4%j1j6x8nTR396-dUyApW6z>(o+L#QR4&1#c27#NwBt!H@ zP373&vmvRG}k|O0JHcS(l_h8P~Q9+NF+H1>oVN+jYbB)cD z#%A*=v3pQ986AYCL!E)JH+B>D(Y+q9aM}g=qIX3?n(u)`SI`V``4rYh$u}nE)QZtv zK)6&wOC@xYN~o~z$(9Vrd-;;FLPkLlYS@Of%5fm~z%HbhazB4QZbyN+$yd!gn_!xr z=&r_6{`g^*=zWRa&k()0O#`Pfh=qfsCM0haD6Eu0B#jT*t5q&|C%D>odo|sV35g@c zN35nAp+!M{oxS?8fbTl^AWD|C&#ry;qrrUladP@a@q)LGCo0JJ3C*OmkQb_fo|&5TX7XOpT+loNnyI~1w*=!o{-BFM?!EVO zFj}2;+xS4g=UZO;{kx{-U!YmuY+&!u4DyU!<1{uh(=b4{L) z*W7Es?(#udFsQ zq8=a8AxqBO1-Jem0`_|OrBX_+8|b=${>BaTX~1%yZER>Dj0n;wpf>Hm?7QEY&qU_$+Wf_W~2Evte~MysEQdQ>RLs}V_LZ!PvG4Zn{W z_RH|gYPyEsHT=G4_+^`$qbp>$UFJ21Mr{I;dW}#q(sQBdHxo~E_s?JVQa2_?DVnEo zsXm0}=XV(<3R^j0D<|wHa>AbG(#=b<-I_LcE6GHT?cl!*3Zjd!r2+j{r#vh&c^>)FK=eTRj=D zbdekKl9=*u!9^}vq?{PR@Rahq*NQK|F2Mc(V88JwGuxoR7Ep>d5FG=uRfmSN&OT zPeki2@Su?NpW*(mfc?u;jZ@Oql;l`kii(%BhF>p-w^d?BS;Oxde*dZAx4U*@WZ3$w zAVLDwh@fwC!);EgM+#j0Qp(+|>o-%L z0<$-514gSAM5{t0Z_ueoSVPpF2ch|ZOUrwB;HSM*<+p4=wailX%hS`K`OIF*M$6#4 z48A{M@cqVKT8N}Z3fO1~5_?%_G22;lu-V2I2a;6$Qt-Xi?9P~b+bk&Qza5_L{k~H4 zJZL_{no?}Nm#+8H7rmEi=`(y(urvgTsL*OAcoF6e8`(H;c=`rSy${Xuewq4-HN(R{ z%3D0$bkB--DKvMl|AOX%=4+to6_urK5K#>zP#|d_7+U7GSucLzV$CmwF6HjUn$XPy z7;!=TcxbUK>YnVUvF1|)EyZHZ#hNc-O%~}}LjrdRkj)2FX$0K@x$G577l6=GPzuxXB##p*F=`lZ}Y_>A}9>^~(VPqVm6Mp%M#&mKC@0f^1b9cQTHd2SPsmQv5wA@UQ5!3*LBZvE;WB z&;KgY_S6&;$BobkhoXPL#A7#$1eGDD{g@T@tU=(uD*Az=y}k5MhglpYoJ{N?TZFloIYJ7 zL3ocYns03{G(e|WRc}S}kh2f@!gpDdFBj$0_GN$Y@R z9kBew0n0a7vwOJAy|i$kfV7%Wo%a0eblGTbV;o3A`3^MsJrVm8G%4w~Hg3ZxYOd!w z`yL;Ieu8Ft(h3z@p<+K0D)tRzw(NUif3vfJS&GuQxsRL%W8G`kye*)kS4K=DzZV1_Ewa?K}!v&WscyOG~0oq z{BMvZ^F?lrvy%Ez2ceqg%u44W^Y}O$r7Q#AGVuL~f$tm0+$6R#N&$a+IqB{YYWwxI zjJ~&wHa|Mf%Ka0vyqP+rC?Qurkfex~;zVa9_{rhC`A}Kb+GVZ%$E>w=78_d^Xst6y z$34TO6T~#y+Ta*+=y>HJUKuZX3$KE~ADXQYY53a%%SoE;6EiN`IxAaeWv@Cb>q6VG zO<{=DJz7)t$}(nqAZE3#M6bqj#POv-buvtU{vwB(rKJYhmlz_eIaup^F_$qw91&RLbqA=W*Fv1@8oW#a^;~i#XFV?CPmSME5;l z%TJqWpG0S>Eyw$EyuZltKFK0=Oz5e5nwLySr3%HH@L;2uhZfEqop+*aV?PtSmF5+D z5yQ3Q6HB zUFc8lRA!P78-ig9=35x$Nj8LM5=tUhtk;V5dQq&G*ICVM0(n=EqPt#O^DVHX`tXhE zkf~PfZcgnRGH-=QtGNB%zMvUiJWd;GzY&J{=@11AW?7`UNb^;sDV+-LUAooV2BL(J z`xh(r*>*~uha#jOLzCat+|Q&bNgv@sN=PbEPMc_-@w?kfC|L<5uS+PYQ)5cnOWPA9-t*UNc9R$DnUATjW#6OF)he1e4jk?rc!H+Cf86BFO1?|_?8wV z&rs(x%_!t(%lN*G?>}LDe>z1-XwncT7&r<@SA)P_p=7~Ls2k%^I@LRO*KgA<-7ws$ zl!)uYr#c2XV*D=)I=@Ing_YJKx)#wFEuv~oWa|dC^a?TxLhMP?&ROcTvZ=Lmp_w;h zge(+4lHY^V#i(dGi%a8i+4biFKry1STEKJ5&u{w^*3$)%!9autpwC_^*D&H}7Fes1}cln{Gb!xD{_X!H}J(f?!i zHO@&2t;T+({mb-+Pz!F^n$&GOcFq!alTF?TmT%zIRqQu{4Hv--#j}>xc#PN21gqk2 zro*KpEgk7}9qDPn=BypdmcV@~2qD2vxv(j7Bd?|Uv1K(bd?)ba4X|xE|EZCfyzm%BAZ8U1-xOj{f<~qoS@m|5V&(3|=)S|= zsC%#?H&u>Wfq!X(g=ioLX{M- zY*S=3A9V%VbD&CdTu!#=e!wfS)j%s3>bHUQ_W;OvT@D zD{Z@JZ!-d`V}PIvG{FsO!zyMy>Nt?e@P^LEZ#cI$))H8*^KW>jhf3koHrB__t6wB0 zF0tm{HUIuw^Y7>zwI&8r_W4)XU{7ZNnv~gmBdW*f6dwhU<%MpZn(ABc{eOqx>>1AJ ze3l^s@p0bu=TlQE#nl#_E;@Y?onp~SGX!Str>2t}s&EICQp?ay7nA6p{62*CStN-Lycg*3b{g4KkyLqhEBd4p+bJqTQU(beLTcqaq}#KL@!2Xs4jof@+bX-Kj}ML zXUwvN4#?yHnK+=%>0leTN*gOrIfPEWlt*VXx3*5xUrB(!xHE)Am@wlsW5eUQ_VY8T zXhf`Jz?BU66Ul&2Ka)0XHMc>4eFTVZ`;oXHNJSr84Ntd&fW^CjCBN_uUxO#V6&=0H zL}f2u!sI+pCMu5u9KH^_5)ruEgUdbm1Mb1^(5dI>qcONw2QeOyn^fQ;z+fWe%y7$spw0=T?+0`D7a74sSB}cGN9R8DU(B!$xt_} zh&5-A10ADpfR($?q)a!P3_~n_5BLm4iOf>YqtmCh)0AA8U6}m|%zlGTC(BHp8^ov+ zBvGKYNnn;atqcr1r0jCJ@O@9SH?naw9G%t7vo;jlQaA zbcC1TGN24BAi)B$>4ZsHS!(Ah$Dpb2@11{zW?tyVjkuBte#8hGGi#yq+zQ_)8vPpI zU``8~3z{#2W`t6~!636aNNfgCB_K+U4SSJxBnl}m9CzEf-@5AXN|~|VLf2d9i{3(Qwp!Q~(yi^=W*4bYckT++|LEcK z|Jb|I9LI4UdLjX&xaT%ntot9~gKBzG{iWPV95|EyA;4F7ej@pnwGLYApxbrOu+fZ= zlDW0S1SQ23{k0(oqd^%P975;)bmX?Wme3Bk)uQ)`+9qcCdoB8ODCv-w3Hz!P>HERiA8_0EYnvx}Hm z&wJZGQ!Q~jc}5PkRV}fqB|cOwA-dV<>M4&66Z1@}uel}bu<7(>lN>sA&UD>7lH0gQ z{-w$Ne{`C-2xu#?Cc%zGLisS=6U}*ak>RviHP;G{tC| zNH|N~Jj!-#k?RkJ(V2a+v&a?Vuxpfp8lmJ&;Aa6=AFpw5wF#)szPNO8={vaeWxxjK z*2OsiMomo7lZ)ge12@&-QuR=}!UXKy_wUT#-4he3%D2u>11-pm;4FsK#~R#Qz-9o7 zC0SUKg?C66UIr|*4MmaC7MW-EUrRB1O@lK_9lZ)3eG=aXEX!`&T1en;VMVhGG1N)$ zw1M@R?7!P%Odta-l3gVG4w8N17{k;C2i4>@dg9tNxo(~+w!F36!uo-VZ+}!T@kOV5 z+g=4XzSc|3E<`a$#HSN5k)7*lfGGY(r^GhfOV89cJl-+=R33qvE;?Ow`XM@%XxdAwNn$1#m1@Zw zw$!=WMl+Z`AEnd#=#;#xZP2egv47EN2u{RbMg8Z{=}XnZ46vrtHJ$!d)2Uhwm6DUR zUJ`FxPp*Yi_S{EzcG->smhS^Lb~94gGUGLJOy}|!BV#@bu=-eubW?|jNSRkG{fec3 zODz4%>!eXy<82PC-8nHgNWrzHW@S+0LZu(m_WFhIu9N=IhbS2&uF89zM!Envk6~Zh z{|c>x%{tipT?d<5hw2z5wQ93njU`nmTjCZ_yiN!Bfx_XhR6w{Z#+SIj&i+?ifv*Fr zx`E8<{5b1L`~qMxNOZZ_mW%BjF1D8$wgGNn6_dkk2=7qllej18*p;NncBHH+W*rRQ z6#!33#Lf&W0{OdfSe-*y+|C2+@wf)`EP2haYli)+X4oQzTsKK$YmrzjQeo?fsQ1mG z6z~HYrnmq;S~|tfl?5y+W5Iav2@!0J4V}=!2nb|8d`#qW2FEeb}oE;Gp znQw{vh*bJ!iKJU=VkOG~4byxN|B7z7!?3)^u=85-4Omxj40AdSu#ca_w}8#SipyTJ z>^1MO*Sri^m^9*0l4;nCzNh3;N}>R-rqpXauqFNi>;sj=z9%k-(7zq4$eF?>}AWkn9s1CWE#C=PiLyOWe38N8J*a0ov3Dz=0&~FLcVI4bxtKDQBZ^ z4Zpav&gjq6239#vr;shLfprb6f7ie|RJ*_iNn31*b=#6}MbhR48jVg$hX9N4cqP2o zB;$l?*ZzJ)6cP=RIM2h14WP}0& zaG*Bk3!V3BV`5s+_YO85s^1zWM9fTJNdGN5e>`@@QP)OkZIs@zQF;QMQ40?&E#;V{ zPPkzz^H@XXRD_Cc+fnYkSJoe2@k)E>G{*nqPGbwT@c$H@w=EPQ7AsGC!}oy9XlKCyD`nRJ#PFI!f` zB~V%drFRIFp5RVX_2I))&aF-F%$B@5CSV&dp!+zcY?$c0&z<@!zU2m;5&WBX1_@&J z;_G?s-_InQ{dn2BlCCxGTH}6bjSHk(ui%LwYhoReN-2_5q^r3Nhy%%HaY4Q0JB5gG z$#Rk1ni%kJW$$c~0-lA0XMvL+TTyR>g0ASkkhzfgA!PPZn%TT}w&;lsa|%^Sxs?Gt z<`8;pBV-RuG836QEisab{W^29LpF=dr_m-qKCs-l+ML{UdBm4T{2dKc+aL;-X|n5Ok*^i)tOHSwW7N|SLQt069#FZ2kVd51TrH|<-P@O9_Rvw#1@ zZO|*bT4fJi=v?Uh3_5$sn76H@QKoEYt3B23Q#(W`v>D?#U`+cOC*gkdr|&vRok-%U z!bJpefyn&d?rMLaQ$S_K^{%+ycf|ERflhG*q*)LnD2XdtiUuuVRYQ)!Y}*lZ5*SVMD^?3c<5m(bm2drIWtU!-yS$s4e~W2JBR`#(|K3Uc%ohHmN-?3 zR;bYmHF`^^(G%G0TerYm6IqPJV{j_9VJhx1aux+S5MLBu)uexZ)@Hb5*gbL@iRJ6i z84;Sp;>2z>ctIazs%#6K3!EPUXO2;d&pl98NF3Z!&F;y&6x0F{d`P_~a-l!JY9~1H zg7}j-%}l?eil&K6zy#yOsQM@LLAM(rha9}D*~^;!4r}%^)R_^-)^f_lN8&b%NlP2a zL0Gm~3)ArsI`y6}Wug-FBfQe9bMD@*JxSz=G1lL&)L z8L4%K#9QRKueAx*Xx1D?9NGwp-D^Ia(99RyLni^ow=V@uObParbYJAo$GKrY(dn~m zW}$PT^E2qwO>;=cv^nL;osvouOJquJMwHv3028r$%J&Qx$`{;=xn@(ka;J!xSOlII zk#IO7EDY3_3Sp@b-l0NxIdG`qzyWonp*{nLwvxQga6iwP3~G*cDAI4%GW}VbFn2_M z$lzpjzFt377&v1vorTvYBK>}Z=CU~~VZst7yhE7qI$#+gbFQh<1T0}mVRatQl<74$w`b5)W#tb+AMz22Y|&LF+B%oy;@zA9SI59&KhA~YHC7QPvZ3? z{>z@kd1J3b6Ah=t4RZ<~k($n14Ms2Z*hcu@=HNRFyO&fXQ?2{mBS9`g0D@=job<7N z_s5eMh1ZjKJ&FIWCvj6(u576l)x@Pwn|JYK!&`1pwjPIK=_ei^E}dcru!v@S?U7(` zLsg@*mc&m0_6Nh_{EIBWF2Md(fW_Lkk*5wqC2{Lps<~-<$`ok}vGIwjknB(9rIfgvSrJ+j5X zo{uuD#3P2~pMVun<*PDZIZKw1ptH`fPt34Cp2Ru6DJ^w*PEDS{#5G~I;ialk4Vujr!{ee{m#qt~Cr zZcL?U(#VpSrbt-5r{TFk4(y80+s1zZ_R*7guM1HT;ai5N#u{#*d>UXMix6+3$`CC` zR^l|FvEnqXU>axQvJKQ_$a4!QkOskIuNjB?=OR*F%Mhe;lST=(Eyp;GC zVEe2N;JE{YIbNCo-KaF!>~`GY$%#9HpI1bVP&pFEmXqg^Q|lWrd&$|J zx6@2?#;>vRPuw}zxH|^(Fb=sMN)bZLL^9ZE-1$tHHr=9=%w)y&uDIS$#r1B@vxQG( zuO#ldr;0_=7~5vp8bN+uDELp{=R+C8UV&4n=x=eo2mmVLeqK1sYv@#_wX38g0wa4vCC1-zz?x=%n3XGX%`Pi53tzG-D<`F+1t8&ItL2 zJYCgck>?`M50Ph$wmEH>G72Tm$f=YDNilO3H^ewJc+M85`^Hnh}&o z>BKy3gva3yKgiQ(gwsOjLg$Cj8KVrv!bxFJ;@Vp(SuypdEwI%-?9jn8%LVQSulR28 z3eL;ocR4A7QDy)OIFCG^xT)NdX8^jao65SWeCVb!dI8I|BnYX~1YT!#u%;Z&21Z8y zyyN8`c-|=}oo`#ez)nGFpk=+HGfXj9_AP2Jy=>!!d#7bnUO6i(XXPC^D^Kiffi~Di z=j1JOV$Ys@Q%+lK8$!vIVjRTg{hk<(U%lV|k4=P}`P=Y~keviM&OE6+Hl+QWI|)IT zBW*d--r-1l0-jZKx85Lm!ALxyCZ93q69T{Cjh`q0T_JD|I56sY>XX zTcIb&^LFkG;E09Jh0YJ5Gsd=6EiJX|oS0_1QJ^RC(g15w2|9#MeGrzy`$bMOJ&>;_ zmF(=81#s_Si?2Lv^J6i>4RH#hEGfd0B791UAk@hRSt=r$cxr^4X(Xb8*-_N-*t6Du z#fshI&7ET>er09U`E_EU9b;sfC6D^r73KeXYn{hsqZ^VNWSEg|*-4L_$$u!Sfs{_&5ddr^+@g z`x-je(D|XEvr>rmD9LD6ATs4tWM&dEMiD~|MHVqSF&W{Bo$Zgg69e<&&c&S{;!ck_;cYF^)CV!oa&I3c z$)+JCHXh~JR>AaooGh3ls?u>9+(bX%u`YqAbPY8t! zoC30>PTNRqQj>G{)O+rY6vORM=B?O8?rw!<*WnI2XKaaHr3mU~F&!&*T7>3fnb2)- zOP(IK75Me3z_0(Y_a(-$UFDnOWPA0G$IKwk;nhv zgY)SK&9(_;4+jrsQ0)X|+YEGf+G(~Nj#G}ZiN`yl_&1`+j#A~L7=Mh@aQ2XYLfx+c zY&`ymeyxEJmZeTu>V)4>Cp-;UD>4LU4MdWH?xc`T0y)iR*rk?nPP33Vx#Q5LzvU-r z5dBeQXeCsQ-LC@d58A!IHKQ3bFXCtsN54TFJwIUw*7UwZM=zj64%x5+^IOoRpyaug z_#t5b7Uf6usm>)*jKYF^owJ3`i;Nhluq@0j%>D*ufAC=y6`7s9Go*S4o%WXITLVYj zaWIC(IkGq3RSNgU>A|7YT*yB6U(MMvTF5Wke;;G>+x|NT{3;q1J9$kqj#8c$Lvb3MrX}*aLQ_8AiT6IjXs$=T9ZAwJ2d8wea6sVINPOgo%>PROk z;c~ZV|84(0y0B7Gq0c@hc40A7I}}C8GXs@>po)+$ZZ{1TT;1KPyZcwVyMI6czjY== z?;v}vpc^A(=^JqFU8C2|{oMDo+^yB8Plov4+isG|AF0?xnPy^gVIR{o!!uk~D)vgn zepM>=7)Ty9zzDZV9u>&m5GY4(JBwmJCx9q-yA0okryO`ujoj!1ot~bA7C&D*)+N0+6286H1@Of^~;I5&ToWU&(d&zYqXd%w`3wPKlwm2H7JaFs*9#LDWtH z*6u5o_=ZROue11PX%lgjl4<4D`)@&97n*gU`Hc(B4}PcGbX(j9S{1+E&W@p%8uFXL3g-xly?fLjK*|BeA} z^nuwofw1XQjSZphO~E$YdE2zIod_O$11#}_aViIZ&4{EwqRoU!Qr-UF1`mE4r$xgT zowVqr7tu*PdTGfF)~$eU;ZPz3dXs`qQLvr(oxY*-fjplN?WtKf_~R7wRs-Q8CHy*c zK0d{KMduVZ;40r=<@>KH-}f}9)BN9F*GznOldE zp(R9R^K-M)9~)1PqRqk!mro5KI?_x#Bfk!v@fe+7BegS?Wd#qe;K3IK4;Cslt@uB2 zgGy1Mcx|v_ZIU{6swXsnbR)d!{jwN7q;b|V?2XS)Az*eV|4P({3ZtqT@?=g5E)s7hgy_! z6*%qjUi(e6Ac4L-;L8L48y@fly#Uh4SB#6Hi8nq9$W~(e&<9xA^G5 z6jWIZ?P6$O#L!A?l$`>scLEjOp<*-Gcr*6ey88+L*qfhI@ewo+X`pcXaHyDvP!_vR zv-i~0EUJs4T@3Au7+OOOv#|rkylbW*6e%5|Tj$*^`AqWW8#L|yT{92E=+)HY6Pl4& zh$-Zy(DalA%>~UDL34~YO6LMuV@}Q9pl(>f_vR8c=5g~BH2ppE>#xw%8y`syROPdF z$ zXxx>38lCrZ^7e;Qv)uSdsAsACQD!z%7z(1wbu<}tD=JH+#TzHlCx)U z#!naJ4vLO$jvjPQsORr~>AynL-g_OsPR$7XoSN=Z!rn^hFQS2-fhO8=Q!h95tK8IB zwoqh;ZQl@d^8uxdfIxFq-gfWjgnDr|6#h-9cjTs~KwzNGR3yTH`^k4KhfmyPddIArREBiBtRP_ z)IJof6N!XTJyUr94>a!&PP*AKM$_*#Q1;D(ulB6^CzJbMw-}#_m;=t{C00CGi+!%S(cOK zMNXDYc2%hbM)w90`=vx2hEE{CndCe)HBhv+%hh#x6+<2^m>%Q!70pVqUf z9wv?`dEGdr$C9J(J-)f?VL zr^vC6-dXg6IGS1pHN@*U-Df=8g1#CYR)fQ<8XUGkshujIxPjKnP`fCwWRtMKisv|8 zeUz%1H#&5masH8X5*#wWq1VY5o`5D7v1JTh#?TiTLu05|Z3!e}12qlEiWT&9Zj`BNk>rMcgVdejG8RCx4OlNz+1lIqd0}XNaa~)N&Wwz$t9DE2Oc#z&@)#R zd3;roe?!w|N<1xOE@Zw2nYE8@JquXfWh&(pa_Y zS!(y=Ps+{80bniUk9JRY^&*V&Qou@C7nOBU`IU>x^MD;iccz44({VPX@^vo(8Cf`` z*N}67%^TeZtls$O&f@9x3D{)IGB2=~Ex*r@xu&a*ch&K}s*X2XkPi=N*eYn<2Q;S+ zJZP();f3NPH2MCWr5siy2}!{ZS)WX=m&~%ktCnAV%oypvq3I=8ir7jK`;VoF^=jMJ zXaf|ipsgbm^8vVVX(XY}=Z-J=J}Li(SEZXA?Y=IKe+1?Ra&aqh8ISZ-V6Nf%tgg@M zZ+upNK=GE5yN|4pR0imV8?-tlxiqsn!^@~AQaSmC<%aj~qW=DG{Wmldjq_v6oeKG+ zP|VBL+$Rh+qsT-iCcvquV`zdJZ zqZF|?-f4MOC4EAZ(v(Z_%b@wh0fr5835u4W=v9KE!EXDu!9FU27Di~BG3=6_CAPix zQ-UJSn>~c)f!1$+FFzIXC4$7ANiJJy@rji-B7_%rySUpIaksV4Ad{+~PLsP0hP0?a zWsf(>T|d*%G6NJIm_GG5ebZ-T!UuO-aJJoZ0KeN+zb!PlL|%32Q-P0Fck}377X?yE{MONvluF_ z@Sznx^rG;g?0xgz9I9KsGqu_aNT5~mEhNvO({AK{-)iM;vK}$D$>r0MO(>y)%-2=i z6WT)w(KmFa2`v-LGO@hM#FD)swJ;dkcF;`-N}Ks$y~e0m!po_(_8~e=-uK>rqq87t zluvXPEc4Haaoy~EEK2x3JH^r0r*nNeU-ao@>)5k&5FZL!whArwfR1~Y%x+Pyot^eS zvEP^3871)(okW32?sDN~`?&Fe=<8;igtAhqS4#D7q*VXll!CI$USj~+$XRtiplKvz z$7UTXg`JY~J)WI>qk}x^EX?sC4|@A_Mk@amo&SfuE6Z`5=d~*mz)>W#j=KR(-v1IV zoUTs#OS$7Xa3PH!de`g0p~y45G1=~GZNGCTdgS@Q=zL}Z(J@W`A_a-L?gp|+Qt@fe`Wi~odk%4Qz0}JLLX8H#7eRT3gwsy84{Kw7~B-YA(i}TP4c^{pR-05rT%j`0n zU1mSgW%j~ki$iE|DG4niNvk!*k|`B{UIvsk{`L?$^WJ2eFS5a%frxPn1Va=L)`0Vr z?}#t#Y`<|Q>y#o)DZ{^Mm^Mnr1sTIwyhJoPPSW} zf}+{<)+wm$Ojj@2X&DOp*nF^LM>dh^N|~;dpKztTZ6gEgqgT%f@>;(F>M0zTBql;* zvE2QT)vY~|GU|;@!%1xE~R~JK3KAKjW?Osm3dwH ziR;SST)Jpg^(ILjEeY3_LWd+>tSo&{@#T;ud&TP$jr{c@N?TFY#N;=;szpZ0*H+Mz zX5W2h+4l}m$axOGbNKzIhF`3emPJbHxk{2QB~=wly%eaTz4qnU8OFZi!Jd3pw^DMm ztTk%C0c*}#P!0Jkz}mjw?6Cl!4ag_MPKN!b7#0GN7qm2Vy_-5la$8!$($N+dXmRYf z>Q58re{GjGE;AWH>2^1@tj56#aTdec{$1u9U{}-X1ndOtzXjMKItF-h?`r@`wNxET zva%FeR>+KFB0>L3%>66F%9pS7zkqc!xu=RDt{Q_dJ+HpyJ&~YU$TX)-bJ~Z@X}tsW z+gAz1@@m3*sp4z;jzjauqPp@so0Rzw37Bkt(S2Sow|2QRs25e24Tn_B0*(!13S^2 z_KMKq;W$I<_mrnOZJN_QWKKg`iYP-W1t^I%Nu{}_;wE(|L$Dk>&g`PoF1oSoMKM6U z>yRP{lv!9$JI}yAdC~(sSsl=(!hS03KcujaWl@4*i5FUuNF6C4_tdLb%&paYtY&E+ zo_v7~m7qCG+*1C+%ux`|vyR68YWI6w5xK*xK${h4AF4o8$fFyL#J$6+;Dr<=dJ1PN zVXk!?D#F*e;PWjmUvT5wnb)xD+qcuRVPH6%HrM+8o%C^wtAa>#s-08qho)Mo2v!`^ zC=^Lzt@IV=gw$$XM8WETizr_JFZxt+v|@K-U#lFPZ-FRA&K^#Z&yq0M{zvsZH%QhnlF+&zifE~!mkivT^uVOc7oZEmQ*_4H zg9kcA&G|Oz<^aoR0eY4qFz+jPztJht6c|l`(LW|IT5=a1Wl75tYoloQRM%Fe!CV&- zKs<7Dc@40#HUBCr$W0MQ;hfnu&XVxHHUF-gtI4I4OMie%-v%r~i&|SvnF=LAj}+NQ zvJeONA9Feto;!+~J3D`1~TAMx*|iT^UJsUqGLfq)sa0fU~k{YBX4*l(v9 z2h{14nLe2x@yWcfPHKd}W3j|-u_WR-6~>%w;qIU%A`XPByns%P3vGQ^0i17V)9m8r znViqEu;u-;>0_flK~|lqWHXiQCsN7Yo_`ffNU4&_SUuvQl8Ra+Cq!gX*Lt99^cBGR zg*W!UuBdUR)3ty&Ebz>JiR1fU0u+*|beKwq4=EjFSy*I1DuW}*bBTb5cNpfq+bH!v*gL@Ge z^>n~)8B8^s-_NPWIm@+#^en&{9|!EJz?gQJX@~gvr?_{-WFxzNVevGE-FJjPepoTD4%Z3T3D|!Luz6sy zkd|2T8hx*p3Mi&%0t3C5e#8;Z7my1-R~T*=31!McuK3GhJZAaO%SB_#2wxXvSy| zXF>B7&&-3L4cF{{otvb&N&3(xDcVv-jgo+BOA>j#n97pExDWO9Z+akGkS}Z(-b=mT zI-6?tjJLy#MRw=N=V8gJHF@J5}*Z%`pA8bvuqJerl!KjInix{0X(ds^JK7K)gD8q#2gyx5!nZ-+Q zgHpbx+jm(fT7$&eM(`p8<@HkTqpYGqr}@_2 zVof2LtT|cpL#%0i)M`{xS$LJ`Qce{WQe`d~`{>>d{WUdT;BT(AU(l2bY~|SJUpV;9 znk*R<5Kn{VJFE%JQ?)Qv3qPS+c;T-}*lI;xk~Jww2rX4vdg`D4QZu17AUu?}p!veMvjw6J`?j#D{js101O<}ME@<`2+Ecza<$I^g_g;V| za4*3T$&1!CyU3H5VySy>JfQXk<7{a17Bp9E-qb*9D`hG8c?;UNpvgLgdQ+(PA)#KU z^**AOnz5`dZAyi+CtyTrTn5ymUrm0x1yaA@7Bng79&W9cLl88dw*`9VtI1a#{$$O` znx9}zb&zE>dzwTf89=F+c|uoS!%c$Qp~OGU7uj3TZt3(^AmUBluGuo9*@<7xeQ18` z045Kc+14}L`a{{)r8ZicwbTPVi4RJp*P2l3qF$+MsfVCxf47R=wm=)uWQTw|Yi6X? z-FaRW;XC!*;K5MoWxmD_`pDgl8Bov8B1|p9 zhqMSJro4=va5yGmfVB}{6G)-b2%5BGS_J=^WS{ZrhFeTMt`)vtfz_GTIaf8G6$xhh zT7++Wx@rpN?so2Oe`0t0HlLC$m@8Z(!EzE_JcafpMK2>GdMWu(C7Sx)-*h{$TABY4 z4;i}x=bZCd8Gdgi%oELerCG1^BlSve1D1<)7U&6xlI zawUv#IEYuFJ%ZiJPY6M|PsE5S#=_@Sxa|K{A3ZIkne#lE&Xeg+oJ`*aY+u__#;`Qj z)^1UvR3k&`1Wtepb~p-HeGb^T=tfSMiu2v+V!VbbfQg?5*mpv5HE8PTr=I>N^z?57 z7JWon))@M3ltd*`LCYyecb68uFGnY0{abk0Z@_M4Eht#F+j%vILj*JOX$-p`9`=o4 z*A)7B!Yk%stWgTlwfgU zAvsOp8~aDs$F#rfDDw|H|FA#uhkeBsqf1$sbApPJWEBwB>^0?FEi9}QJ?2=8uMFJ3 za;a~gSB25yc3sVGs+^7Rtl#Pjl`h}76dh$kb3*ecp!xRjyNE8iJ0zikNtV#$s3oD6 zpfZRoAIkuY3+(+?VJkAlBKZDW1#oA}4yUb`-WYxb+~;~}u9yC)^^z3q4WuMw?@5|j ziX}=yBXV!mkdHDf##6v!oH1h(y?z(hf?5f3JK0%CL69jd&Hw$Z#8p4c0mr;QUdB<;Xlo;yDukQzLN{ z0x1oW_EM6Fv{Z>&@~EmyH!*k>u-Azf@N42dsE|+$q5H*^h|t(XP6OiE>1q z3_BV2pJLb=VqPdGrrwh*g;E%3>P@SS-p%OM*v}hapN_Jq^LO)X^2_RXP7}Wa3jf zzwm{&wo78Q`7CJa{*?Qu14gqMk~Bk-J{6J_xeX6o zQgvC9H09*nN0QcxHEo9D)g+cHG7(V^koB8bJzA!z=QTzsA+S zK~s3Ul_`Vs{im4$I2-6`OQ08$1s|6{06H_0W=7J_WF);H*Np*^m+(}&a}wq?k9W{& zE@eTIpg8u`keFNBxwZY! z);5>k9mJ9siuIo2skRm=@&E&%Vt7b3w0h2-Zf%9Wl=ctM%*200+pnrW%6wv1)4nO~ zVag4oYfi)*a_5lyi6K`pw{w=ZC(Zd0?|zEt$C|(K?c^O@}SAt6~&gj&deHH=pHABey7v z+_T7B$aM_H-}XO-=boYQ6rToH8m+Z3N_?o@*tFpJQpFz zg|<$eIUw%itc96p2Rw~5-+`tAPu85Q`61RM(oWRqD%DF;+DL^#)3RhC3z9MNA!z1{ z?ulw;L%Anejr1mWS4SnucAnh*jd?a-9jO1SKh6JV?@Esw`F&+XsKQM^+3=eDLwGg* zd2K(fEO}J&fA#}|Xaa2X@%apVAa^12A429N4$R&_lj`2ry+I7$05xr(l;Lu0pY=z| zJ-4K#3rG#{{)uET0h{&9!e zA2qw(&#Bjo-5Q!f`dQRu#W6DZh5DdpplO9-P0ckm&zYK7)w1IN4OY~Vgw}H1l`P` z3U$C9m{S6!{Io6Y4S7uO@}F;^`A6G#H8s`DKKz?TSv0uB>sX-2&g$#ai6kw4cJZ@k z@v~hpdf~g!-1pgA{Om5O{bEHSC2`|(znXE;b7pRO5J*`=^!PF1A#8}_g)o-V!T;_9)xEO!#v`B~^ zrmq{DZ<5>xJnc0&gGf=AT5qZK&Qa@muYKEwfYDY#8&{}p7*MxPgQx@^`*D^F-d$-W zFLa|V+Y8EPn%CZxg0`PkUWd)c@w9&p&NS3@Ls>VJlWr)p@A1%$fNjqpk=%cpBA{d_ zgS6Fp=)AdO^Ny01-r~G&oj1{oe0(=eO-qKGysB#K2hOmoeA+C!n#NYs*gw`ZX0sRS z$iOxYw3ZDjb_O20CFhuSEPn5!`R^WHZzzR|Nhu$GF+vgwM}A%VF5zQ=?e#D%`Cq~4 zg6x9qzXMsqty@}xac-a%9l|F8mNAFybGIGxky*L$-Ghte`$gtz#FDswj#y)JjR<*F zo97Q?3fChx;>|3x@VfB&@8Ffy)f;sf!*<_i7}Q1r#YZpMhqL@|@LHVZ)4>vkC9Onx z6<+=EZ}o4TJS#6IX)#H^!6ZGs6Qf&>N)w{&?MK)Yf=PDmk#N;Mu^vi`|H**8r319s z%WnSwwv@Med%>3hwmd$WUbpW`5SJx3T4JN$5F0)JiOrVoND$!+iYm~&51=9~iZE+G zN(kRm2fl5@a*K2lLHqc`nu&z&pU77M_PB62Q`uK1(&|L|jZUPe@yar~)-oZQC}<0Y zriw7yth*p0CLP^~l{(3&_lYvPBTY*sGzXu#SH(QjcT{7^{j#oDw>ZjoN~g(alJ z@}*Mts?Y`51=)WIvSsVxdk?+{?mcKM5WQ@Gtvh02X^Dp*8yCG3srv@mTRBG_^d-16 z)pmaw+ROg1`FJP(OVd<%`NEek{C9lePXpF;>*z$_(hPLNy#vh~^zJhqg}omNCffn~ zNa>`vmSPtBvJ`7tDa87+5&MMFDX`f3#I8^5KlO>#Xu&xJTC@Pwno!%^pp{gV;yn+3 zV)H_GnqJ=UddsJ(y8BW;@ankt)+_tV@cINv%xvqZvyM9d)KO>DIjW8gw%I!9#sd-q zL8`XdM^eh6jtToC;{Oh>yF2biCa;TI`AB0)Djpo=bsZD=IP&4Ih1inK7wNP}r(YnQ zeqg|vBHPftXmphQ-nu7$A`WPyG_#gl+5zJ#U63E&Z*D=;N+^CPnt~Ne@!QaRYW0oB zlHqHCgjy-SLU~sx?{9?iKK)nSN~wKXg}!A2ZB3vh5sbNQYISUs2V6OHLAmf6b!>SM zoO<_Ts(Le_MKQ8`mQRR^CzW`a)%+RDoGi=SvdsOCW$p*a4A!ZABxn=@)!89c95(fa z-6XIa&?)@{ncvhLQm}tgyyhi^u;|N>`Is`gLM9>ZvwQ8iYtQ|KJ@*IDtYS@#Cnzz4 zHg%|_Igqi;I_B8u06X*(XzImonc&dUKQ>xZ4fR6&vJ8l4hNiscf(`ZzLeQ~sshDBg(Z8nNDQtQ}=B=SwJd-}`sf4PCJ45uceU|VsbNkn4GYXbf zLb^&w&nh9UTxXvt(6H{9+?k+;9cIyPREcaJPzKTk^@4XZ2UXu?4c9BJq<%4v8<7Xw zxht&-t~2O5gZ{=D^am@gcyGK(g0OYaQaVK91lF)w8!5%Hl~x}dJk{QF&#s`!81!-Q zG)Kw8Sm# zT7QpGx`L({(dTc|T&%eH%U0Us+M%5Y3SQTfbv-%jdV-R38w5q`1WhzZQvrU zW6-n<-qp=(`KE=G&GAFlXA+r_>E}T+vv^rUa}CXthUO5rZq{LN7%0sF(YQb@We)90 z5eG_0|3l`ZoHDz$&l<}Yiq!Ddpm!Et2xqrpa{R0xH<5Z&7 zpp~~aHSf@HGL(tAm8jN`jv|wvL8fuW=g>6HbdB;lWIn!YUL!MivEV}HLgqQh+(UPx zR|nxuK<6G>WMVKjeJjr{9tTnZ|3l{8%ZcH|ZumXfLir;Vkdu=vq}&S1mS<+BJdW|y z|Bp;#*X7S%{_KCtpN-~ZxJ|%qDySMkVpeEvY?TWavZHvlyP9{)+r&_K`ReyHFD8<& zJEuIu*(UQErE8R)G)kvzZYc$vqHkpP3O5=?=*$-CAdp z3VtHfm{LPth|I^t(3R&plUdg`ySCYrw%KA7)R>{ND`>hxlQDr9JGUv=@|bSVAEY7d z3WQtRta|y<$K#R8qg0)<86Q3<4P4(eNh zD9F&o#Jly%aV+*AAMmqkH|0SpnEXXXEltidk`Y413+sdW@0n3h2QJZYMsWU{wJ3FT!>*F++>j%}hRwOp09F?Am6}+Gcm54_8L$ z+;%fq?NCGCLfu>Q)|!uFGgIG3;#6J24LMWhN0~#yC7L6>@$n;RMp6T7DO@7;EZy}R4?F%=X$eAek zGGreAXO=Wu%_pn*Beg}D#ShsuKepBHplR|R zOLD!=O43(Vdns10|94pa8#6D5OY-GOaG^xSwGhqSY1 z?<$`=(9~P8Berj}pU`A-C(74B^O>nhEK57Pw6iB^XJf?HH>=RwE(24uXZyZi!SLA)tvl_&#XlIHI0;McuE@YmBOf@ep_e7xGYoa3&noI%j zdnXZZT(cZRrrx1v|098JeKkczzGQU~Q*oygn@{#i-sRF7%_Q!jLDW>VmnVrpgQEN{})|JmW>S~}~FzGmi{nJ3N6!Q8n;*(o3a zEl3d6H<(_ub}Uimp-kv~X5R5=@*bi`H$?4}rMP}Xb@3htREQ|!b=4>NaBT8b`mC{= z*wW7~{p?BlS*O|}Y(ldtptP4M)Gjc+^*T(a`(b$Ar-AZal5jmZ@vG-#cfus0yv_~w z_;~WS=cL%Wovho*S+|qT_xoXo$w{Ep6*9Fz#wf#E?=z0wPRd2^56--O*5vg3)B@!m z)WvbLnpz)>&HrQX%5od&dF_e_P#i?kyU|eE{}L{gFYRtKrvEMU?8Z*{NPoo*g8=7}nUuN%cC0wc~Z}!&sV_rgUimb^-QZ0xX7>Q9D7B-atks zh=vvFXc*h5>f==EyZV;_3I73hXUnTu@`rK7BqS>$@>Ne_J04a)0hR@A0d@iQp8~A5 z7*s@ni*yid3bi9b%1l%TXJI}C*m&RV{&j}+cUk?PfHjPi@7tvr!DYe1##gPE5*|Y~ z9w6&UQeIQ+nqq%qiv5P!tkqt_IYBAmAfqyP*%F{wDRaZ5?VQdi4xYd4H`)Q`tTN&| zIKyq`CdhS}(+Q8W6CSZ?dFl`sHWxNugU#6`U06DlPy^v@KpEYEw$frtv<*D>()~Jg zn&wk@uYTSr@FS!zVL}TdkIO`W-yzO~59oAsr^TF$IbXz_S^B1BF!%@o@oo_4848V( z=FNsp&!UsQI?Zt0($1zg&-||s=FCJ%!s)UAg@k+v&QHuqO18pHR=CNF!cBtvz^WAz zmRZ`#46~CSdT(Xm4F2JBf`(sug}*Xq++-&ceg+=DyGmiS+uVSHr zA;jq_ox?MLC1hD=({(oer_QEr(~?S=t~4zm)#q%Q3;2c=D|Z~{0ej?vNjqoLjLsh} zn73XB&YbBgVUiyUlRg0!$yWF7>fZg4?%k&uw&l$@Y6D8Pfyg#>4vnBwpcnVf?VQfx z8-V4VC$ZQJ{QCu1)j%_M$yWjPdSmF%B_~ za?Z?lh*!VS4qi3H`EF)2XGAn%xk~x_jTiAJnZvZREt$iTIs8*Hho;rGu_3gM9mH6m zRICs*Pph<9oHWsV1F(BChpF_H`_3su5(XLK4q%_$2OmF)ANRr8|NDrnOX|9$zT%Q< zeXG=?flT3`sC5V|20isH7fzVsTxP?s#N02ixf??-$FJOsqIn^<{?@jjg3K=Hi*&#%u=yhB$bnX@k6}+BHM>yRrPK8`)gQL3qsA8t%IK! zRz31kJuKD3kEkA=UM`^)Z_PV&o;5E672N9pDHfhaDHi8~u@CWT``h50v)<1)F?&sQ z7Ohwa|E8f0X8U@)DKZt`^HYjWjypAn7jZ)+ErAEKJ)cE`D z^^r@-{G+xol(TxsWi8zKSf=#Ar3o$B>MdNog|F%@R3{xm2sw`il4h_2(Ocb%$%a+L zPeb$TWNh2*`ekR;kDCm$2C?d8#+YwBb3X-^X-exRvu-j!ag+I$^j-w##5wAW613Q$ zdg+im3HG`%lbl4R9O{vF7Dno5a$gvk&Ikp`;a3fy&zMXFDV8f{xnh3874!52S~ksI zx`47V$OwbdSRqmyt<>B{J8>?h8}d=fgx+umu6YZZ-Q}-TO7Btke_#4RNe8U}oskkxz z-Z7z^Bwv@y@I=vQaHRFdU2oidaej+f1Zb@%=l*mgv(A1eIdYAcWCZ??D^g3xmn(1f0T;I#}{S&V5=d}slspsCn z$!GjnQYe892DYf9%@marISp@srLQ+b_>SlYz@{wm8<$eXV9eLepXXP(NQsx2Xo-n_ zL`?LZXYNSk9tP1%0nrViNKpu(ykYAp>A7d_AvEbd>+=DcGRgDm7AFp%-($_a>@l6%rQf0H>}2V>-Ow|vDa`Ac zyPml}@yz`OYf9P>t#-gNDhSWavFr?Gig4>7K{{b(`R0Rm$H}cz1o2^JQD+iUypA=G zPo1Aw6P;y+8?A7op9nYl1~d~%?!6jprn4KEE0ib*nnq8~gKRrHYaR&tXrDF3RqvUA zGpSxZ%&u!7eFmC2rNx?yHDAP&R9L@gr)2|&`i6LfD}pN ze(a(|ZK=!xBjCxBN}bVxBY+UWUwPCQVab;=Lu_dy#lAL+oQ3c>X=XuP z&)M~y{fX!7(*mK~hJ>m>=3GHM6dYSX*BF=!^~UE;opEFP60i8~V0oa@WbPlQPSsgJ z=6c;d<@k~Na8HTASdZNG$bHo#cgoLm#Q|HHL#Kv7Db`@rx?!hn(|XF(NqA)Hq+6oT zOsXu2J|4Lfs7UF$a>8ejnNqCSz7^Z|6R~~YICR#=xb@NihZx9g42@_q znjM6iK;0q$vny^X+J-0EktQL&>+=3ens(D2br8G$9)&=HW*qrCWFAkNkMTibZ0k9@ zp0h7{&i2$oVhB*@S%TjNR2~XyTk5o-mvJhjM8A#?;v3WZlITxlW=rxRLGX+@MJB)O zIUC2VDxWIwRl~wp7Q)Ixcuf{UZ`GQ0hAOp!Z1ZwrUSZ6jkc{1PId$ornR@Z}_blHy z-Eb!h!F2XC{K96!l+1I^beT&m;jwn_6FQxeE(_flQiM$u2u>COr0| zd}<3cb6YOX<>Gvii!;|zxKRh+Y6j`75U2#%TR~H$!RLtcS6R{Dh*NPleQ!EY@cyig zj7&z1d{z5c9H;Mnf@V14Qt&MW-#?|`t3$DN9kB7pAgT^UhXYPMfaIJ*PTf@|V85J0 zC)@7ys3;@FT_Jwp+59vZSqYw|e3bEfXX@8ErO`O-by2jO?7+0UB zSSqP)qzFyAf^Z~o5{AaP6K*LpmrDW5X;+~;>u>3<&TmFy-WFY+Md>xq{8%RG5p*cG) zsr{1Lze;M~nz=g9mO%p9nn59Ua7i_`JgA+%gdUQq?xcu`s{H2dwj`F>Q@%=U^h}xd z+)=F=bj_eYF@ru$rekQ4>5b{b83ZZA6a|85ZWd7!wbNUpF9AEfF*{nL?1CSSyFbZns(aIGP>wpX=IVnF%t1rc=cm3!>6lE5?M)PD~aq!lE|K3B(-3!$qH=v zmg?E((zgc;rOkS^o=;z8_=_lPzNx?e;ZMM-t9*p4mTapa&?oz8)%<^t<52#4PePW+BQR?&%TJ|@I|}_ShB!7V6!LVkp0c?Q!nCte5!c_ zETODWq!o(vGoeUNGpy#`(Tl^_HUv?MSwkv7Q+j|cOUh^0OM3Jq-aFL@v)WzvpxJ@~ z%`XG&Q?~HTzJy9ksPs<>mFh@tIx1+<>14AEj!rNtadY>~=YsCP1K9ohjl6Ziya(Mg z&vv9~9PpgkRCuLogYO7N1M=I5xCRnN1QX6A-9(E9H3blm*_nxHp+{jNj#rcMK z5N$@jTNz^{Z1)#&gy$?w*OilgCt>^Xe&eXVX4o~u{>Tjb4F?T(5^+b68Vw}Wp!j?S zZ!&UjLMcv6t8dt(FH;;i?G}9-^IMw9ulReM%h>SbJLBq;$JJwSevZFSp}ssc%R}=b z4-Mz4+t%Bx;dhW+6iVq8ETv?%72WuRitr7c@iKw4%li-Ah~v^76rU*o;<|*c4BM9H_Bi3AimvYa8LNaoak-~ zSJB88CfBvC9S@-oTcfZX>3^Cu|Bt})9=MCP4o z);@Sg7AWT8pUAXOCgg0VO|$oxKwpqa$bQLPTBNy1^DU&=kfKWg>)SYMJ)rb0e{4oc znQBjU9)jk7ocK@D)Q_~Y1CpFQT{pCvS(0CteHKS zNfm4ggA`?mHVkqKDLqT;bU=u3fo8gSJW>C^J=PTW&-JWsnS5E;&STAIc0feythvsb zZ#rv|TH6?E>muF4>4P998`Mrsb8fTO17X(}Wa{mC*7qesff}FltRqJD(DQac&&;!% z!F@qTX%xEpO^>VUd|q2=qb-Vnd-ca`2*}SuE2y zkaltzXyx{T)_%tqeOb`D;GfV$X38g~a6Z7A-)<)u8P{2Joi*Qf)|@nJ9$T6Tg3QvP zgfytuiTj}Hd}yFe_`&yF*SMExoi~&96`C1SHZ(r1R_TEd&M(jmcc+y#zq01vlr`Uz z2BqnM9T6ltLG{L9qgNTFN%J^}%saOe+RvJgl+zzuAVE|WK5w3VhBQ5F&9iHsebYQk zxdo{YuqFkBI76My0B3HAx9;mBsq(*|sW+kNAF>Bc^N4GDpJo;FU&6ij&9j7w*F3xC z**DFzb%tl@1X(kIcqi}{73RS3-pm3IY1_99>f2|{v>S3DLGoGnu$?ty+YX=Rqkf7t z%~liPY9f4F6CoLMwg4p$kSYe1-JvGbT!owTL*n+tA9NdMcmn9Xq^j-xm z#wB5Foi*24^DSphEd@mhxc0tfkYp&cHt3~~LYzjKd=Q$#H=!B(Z%xY)*JvQ!qT|`n z-}}}KUCj=w+2LKy4no`ww~oOQvbC-tRObZ3DNhmfG7kkDr2ne3|H+zp-x3xH^>Yp6 zES!|-JTcHSXU)vISaY%Fn^;q(XG)Sl2Rca5R(szJTB)tH(XjUenef{?^0%#IADXhU zChxE&XG@u`w3#rOZ#@pXnuGMrVKY5YFPOfBV5($AS@2x&d=oqer8&1P5c+VCQW(4! z2lA|2XIYtX=zww`p0?Xp#-t*2UDNWWV9kMobXGzwtK5Yre@X5Vm2g^8+9joZla!WK zGmmaChBXjphNzh#Wb_aX<$h>WyZNQlO?bxcrj`*Y(^VD3wB7wh%;+rkWWHaj!e7`k zMbflZLTe@Tu9Z;DqYhGmKE|avTcE_I*&`V$TZ)z*dUtBRnHDV{YP(8z3d#JLMZy?4 zr@(z1%2UHF6WwReukf_I{YNc$E_l8No~=^mZexqQOdyRC#J~xIi^;UWd8F|30?%|q zf^d0zrXBXA2uyN4bTXyzz@X6c;CcV;`3;^fzd9inJQqCQ0Z;EnG1Wk07>HDd%FTh( z@JLFd+98FI<`2C+-10xzGbR3%2r;T_&Y6>+#-4cprt%G*IdWd9(JM9jU8&L0g(h1- z%Uk_!nF*p1LCc7xvo^y+UNN-~ykSVW47Yn-V-zX7|MB+BoD8#?oj2S*08jbKp00`4 zYG|#7-n1Ih>@GYUNO*t*Z&uElAy-uQ?!6B?2+vz0KKW4jkR5n3S&n=?dU7JlgecCZ zy**R9|MvX4xh3PQOUSo`eD4zSwaU3rhd%2Tg{cf~twKUfNqCylvCXah4(<9Ud&X|6 zmoYhB^Y&~D+}n)Sr=3;o{=@SNG%2y-io#q`m@kRKe7gCsPINaSaH0%Sy+fUyfpQNK zYNZ{#g!;X4cmLFqS>v;*bK9U2o3ow;*ay0>{R?23vMmkK(h$8wL-aIYO?qJA3f)*h zFciw@0^x~sE?yfS1uWY$fF;g&b!8h838~R(fVKOF(Qkki5S`;WE4XAKaL06@tfR)?l7~d7pZ!P)xy6&~jC+%dJ-wD{H!ON_@%-XLoYd;NG zpG|tE1cas_vkfR)E)gY8-V*m3ha4{(9&hBH$acYz9fp-qk3Y?5mfb_*EQWo?jJE0= zR-MDE>KvX1EX`CRmkGTHf(TA<#0q(K>LajtKNO0)0ruV-R(909*(s%~9LbcCNkaag zOQ)|4o0x3H`>lAtm&E%$4cMklE22Ycm^CC(ZuS96RB zF^67aQ%)L*?_Y4fjl_|XtT*g>!~Uo@Y{FKv;eduxK<3=a2it_6Q|eu3%lSY`r)(|v z>4phh{#8Cmz6Fe3?>da0C2gr=`8>t%1A_eYH)xZoyR1CGl?V8yJV5QGZ$TxX(+PxT zgQ`)XcBI;fo$x@H(l2=4Q~d57an#s8TOo25vB-+2@oB!F)cLg)f{b_xB98yV+XOKP^A&5mX4#KX*=*@y#V%(1~`8I;O`f!dN#SPn6__bQ%|P>_Wp|L z8(@9AJ1@X4!2Tq_61K^T1-#P$NkgC%VdyPvrZIf#(E<35?C>8~S0w(tx@J$9(LGLE zG3EPFE8kwMNU>H-YsK`lR!ozVj#33eH<^S*g3=3uMGs9XUHE_yQ9h9F2e9ByC%2}} z&vFGUMEm-8y0tLajKgf@(Ng`WSlroySnE4N1Shf)s%Ftm)3ge73-zv0o&4W6a}tfu+YhaVV#M;*ny`SwKJ((b)LRA(?RJx!{;*8?ghxtF2z3!ZxsXDI^ZN~oMw zgTwZ>!cW5U{+8(*Jk31EDx+9s6mKe{=(%~zMF9s^5bhIVnnF?}>eF#(J_OJI4yONN z&&0bD2u>;gnF5i`Hv$!*^Wb@Zr7mi@Q18Zu{Py*Jx1oPe~zR((DxZJWU}X-xU=S{f$m?#GDp+F7kW@ zc|QFh4X#5XXOJufq_nyV$V{%i6g#$6@{e@G zYIB*3X=mwcf`nJ)ek3*LY=}FL*5?p=e=7dQvFs>oC|*PH4;zY0kCG6W$|Wx?L&@C$ z-K>q~Udw^JvE%CHr~GCBJX9`6@LO z;v5U&L)ZjDl0YnZm&j+}BX@Z@_>*4+u1 zQhY{|1_z;SRd4TnvL>WuHeY7*pJg_$*~Zv1y$7cRQs)F$9^iy|W=q)YfD-r@V4qqG zQ(UwQzvwhf*(FR)OE`@CZr1Nl)=*s4Z>#$4CDm`wZ-rACBQil??;uzUIBSDK)i6~} zfd{t27sSeq#5Da(X!`PGb^gQ78Ypg}c%E1yjz3v77}K(|E<5Xwva^;xbBx)+dgd+l z+n}V@AYJO=W|_kd?3nZe#bMm!O=f!p%g;>24=9`dMr+#oT^Cjt zR(}#!jZ*R96Qtn)u_;igF(?xctSPb|#p*3%+=X1zj*y>1MfJ1JQ4<+kHjDGtOZSgB z-`7hLy0nN(i}(^P;sdYMJ||LmKwPwjxlJgk8*tQC+Xy8;5apsDbUS-VKUGeD!;=$o z{)0@Nh%q!yEJOAOY;a!~RgvQosJJ+Faq8)u`T#t!P$^gvh)x4B7pNl-uxWY79Es^b zG@5>p{jP)iCp_c#x%CS?QGRKF|MS@(VrIFB`%hxeM_j63_DPZrbF5OTRZ8`WQmO~w z$w=b4Z4Nlv;5hJi{=lB58Sz(a$*Ynbg70blc(U*+Ex?Z zUmks9&*X_|y-3%K^c64C2jJPXdP`%%oUMSERj5J(A|$kwK;wA`o_f;;mp{Zlct?vw zk&!-QlsF?3r(mYD;Q0u9etUanC)DLqT`tu(xm0_iTAU23O9x3dp~@&Q+f0fm!~G~c zZ^d%wO?ia*J3KGVC*naQmj=)>88nXiztcjF1c{ zBNr%Mb0TStwH}1$t(4!qO~1Iexy=z2*IaJK$U!P8(rNH~BsHJ^hG#O>pjhx+@O%$E zk&8}@4B5#+SQ#qf=9Dq4!y*kibXeJH+-|a`#E0x{Zdo+ttN)aPS$xw6o~PT5`zfJc zS3}AYD>;89=f5U7{{eW;I)>1gAe=jhV~2{miFcdlnBt=zD2dXoQYPK-!CZ!0+R^PQ z8|Tkb3ujFxa$axh1Mx^-13?+LAmPQFi#cDwoKFiCNF;jl0Yu0k6DznzhY*fgCU>@D z_GDf!|tq@G`Z*%usISc23wrPu=#$#**AtI^H{gj zbvu27KWrqP(#X3K#HJk-BZHtCkhE3P)Q9-VBeDM$0Dl3j#2;3+9GWP((P`-p z&oOM~CB0wL`&UTsp9U;-mCDR8n&mBCe{+qGjc|uVv>0gZY`_xlFf65@>y|icMiSna z<39)3XL{Zk(-K51LBuNr5l;iQmR4vq0?J;tEpdS|JcBV8@u7X_ft2pYM&dmOjmWmE z{tvK<+v6FLPs=0J`y+Aw8?b>Cye8rwI1&Gky>m-(rAfB*T z#hE{c(4UpLw=%Y*5Rs)Hj=$?sE9~OSzV$!3Bi7XMYS-_nAaLypB{4#uWwg?oM>=L} zvJ2f|JN%{B9aFF-NnhvU#)g`bpT|41$By7{OJdB#Yv;6fPJgSNQ}WcCAcD~h;A#q0 zErIEl11CkI9s(4KUHGA3cRFHCS?!aaWU<|bs+^aCVUI`HZ-R}$<=|fq{vUDhzuXb4 zN--}LdKnFvXWq_k2$0=cPZdWyx+Io6xHH`py|*Oh@LzIkl>Kvp{Ev;WHy!a7RgS)h zqKhc{w<3z##(5}gkTNRp%m!r|fl~EaIFsvvWH{XzE%&0z|2o9kSrP}ae1%{jCb#4f z9%m8H5FZb*cyot?p*d{riPxU^C-%fo82v@0NgG>G;|3#)Ho|FQ#(p=Jf zlQhX{)Ls&xZ;9jy845Rs-ZgouefH`HrFk#K?P_z#J4@Xl=k#eLL`-2u9-hw9CgS6B zxbGvUh4SiYS5Nz!>v*i5fnl5}X~%yJjndmTAths?r`X8F_8 zpoE%f-!=GJ;k1X^{MOSZVOi2#(tMLNiK?j3fa#+Hm(Ebc2x_m~lIY}m;3!ou*)JH6 z3g=Fi3>&+AKCZ}yL)pTg&XeZjRnUzzBQh;};Iaq)h&}L$X>$?}iZ0-l5ty1nA#xZr zZPK({+JR%Xt1|haGIyrUjsB^hM!+0OS?Nj=`&KmZm7+8{CK~QIQU>dB!?z10q9thtJAGQn1KEy0hicd4HFd_$r zou|ylX55?ewBS%(=J{ow{|WQ_6E#yxrjaLZiQo-*G=j)HfVp|a5_KF&8NOP6_)g8- zj$U>>K|=KFoT+3e#u}$7^YIGkR+(XvmP>xQ}W<@Og%W$9@22}9Gnt526xP?Y7@aF=5{s{Q<327EdTbefkc?9tE z36aYLrh+MBi+pT3yE*ahIN$Apv>Q0F$XsG&}H8WSNNJKOOl)({Od>MEP7Z2m;q zd>M*RVp8r@083WjG7Ci41Y>S`8BM(%TMhX~t^8v#rQI+IOs4#W&c)<8Z}Eq;*XYVC zFDjTGFK&^3cL<@Ih{+P|67Anfw2BxyU7;%(aPokv+Cl4f^@+)<9LQMv1&;ei(fWmV zZabYQ%NH0SC6nwaX*#XWK3*H)O#mVqk;UR7EH1)Na1maXY?MAQ20>1x!{)eyvV}Iu z=vh)7GkQ5F*?Wg&c0I@5c^%D`;(A8*mu5*M1xj`~tWo)s{5R^1`^=(g0*=VQLlL4+g&;1Y;;fzRdBxf#rMuzaS9_rBy{Doxe=1f~ zF{f<}b=Ge9B@+@RT2_Z;b$FB2A=BU~QNdUcc=iFc)!3k6DS6Aok4y6okjO49AKJZ< zW}=+Fu3f~$jQ4@`uRW+fz7V~AQ1yIGjasF2mD1Bo=`*i3*``ZP5H=aOrU^9*!i*@j zj&Pd?(DQal_~9}7qcUl?&1F~pitLxbB-^b`I!&36w@Ej*+nC7HIuTtbqVGBp<(UUk z4=8i^Hh~T(mJLJ&dyy%%9dIE%A_q^CgONAOpR{|cTL+Mta3+GOr!{&jN(N(Z=_i|M99_HXmrM^x_a12F0UR&%Hk0-6)ytT_Y^Ji$C6P5MLT=+;$!VK+COqL9#O z1L))Tmv6fvG+u!%E3oB90$ZMtCSi)%r+^gMCQxJWo-0s|(uPV5I$-IwOUifYVRm8r zxL~`fnp=VXY;(ojx0%%VwB68SX@0Ak=%NdSvQQ{*LZKw#k><$I^9Ctu-k^FhAZjY! zrK=xnXdg;*qvn2}K-u)yhE|ep)`d84IdnKRDbzi$es=Y{_XG!y^c%)mqeTevqM_Tbn?}|rq z%UY&PNIe|5j1095hEc1}7MxqeQFY#lN3x6LKe4Ly7lfE43}*U|;!wV|v?(Q9E$wP) z-_+9L=pM6Wn7BpbTXpcL29icCEik4W;BIbwum>g~p-b}bg_9%eSJbw+g^=VEr_ER1 zJ83O~)*|R_i=gN-tn~p!HtGV60zpZj25Qybdtg2!P5wwe`s1`Im%K+RN{sPkMQ{lZ z%<`X<=C>U!*<#`@ChpsqxZ17cG!;;a0&{9mvQ-EfJ+yYJM}R1HNqV8X7c8{D2ohwa zuSL+NQ=-J@ErMQP;u0@Z(Lxoy3sp3Y$Fx$Rl}NzG4Sdc5-7GiiX<|9%thEO~6xNR) z+!oCc{CYhRCsg4Rqds47)=J>YwO_gRKap$yM9oATqNyW9!3@ld;G+i^M)4^|bsSPA z;w9gOh)KTC-lXZM`ZZ|==A?X0k3Z>M^OZ?660iO2+RwgeKWihqrIMjp2(a}E1-Sva zOTpQF9IJ!F%hvm!5)Nu(0ynHsI5~L1)=69EH~{mr3+4wo52CxVWh{~OD;&wt*eS<( zuO~0{w8@uQZ<+PpWY!ZJSyKxTN*n*H7*xK(Hp>{@Ql~gJZsrHCCt|xMS`DB~^$zGq4qg z(r5$ni4~k)$PfATFkj@pm6ktJly20?%JI1m!lar*E$7n`AD%)~->P#vLgD2;Snh*2 zxes^@^-&x$Zdut<7`#x0(K$~aluuOWWBk80FIoEM$ zE0pa6r1wX4{`;2fcXhJmYw!61CNWl(B+6%vov*osbfMlC>iu1)_ij^0ZULc&z|?R% z73+|dYL!w)97DZt{=7T3cfX)tc;~TGEb$jJ$U?VR29(oYQ#?JC=Is?Hqp+;El=YVK zrni(-J65#>BiAiDP}}AX3ZUr`Tc!`nA=djtX-e#dXK%gZuM;PlQ$joOEd}$#y7_(L z^c=V*&NXqqY2s8FfJi#Q)cR<%mD&&a5Jd0hXZtnzb8jD{8NZ-Gh!m7G z8J@TgdVFPltInJ-`$AzZ6z027m}s*M%oA*i0uNWHT?Qy~lQfug9s=%(KB}Gmhlvv- z|B{m;z6AoGmy@E8+uCmvr;@C@ly#T#w!4&QQrR1H83P!jLdlBIvu&FpE#p{Dis)VE z`IWRttQp7?dhrYRLX7^P!SJiw|)wDd*6Dv2f)JnaSLr7LSEUTdJW z271#Ph_ID1N&`z>fpZABCWmGirp$RBmgYS_tzU@t$w7i9zpQ~UERnsL927|x3Ui?_ z--N=XS(&L#NVyPj=dEg1gke$!&d9|NLA}K8rWIW`w7lEUlF`@WiMfUniN3R;&C0as z2aA62Ci=l>G;-w4KZ_MO_XN(?VW_4)saQT-H6N^jc$e(XYRF$sTHlPcYH{AI`O4#o zF|Q5n+R(mfL+e(_X>M%VlwiC0fS9Agv@mx`JoK1d&mYX1+c3IUHC3+HU>_!T$1Qs^ z^LZxsSENZH%d5A%dT;XTNy9Fw3#3^Fu!n)yGN5hlgMqWyJVf*ozk6AIZD`Zptm#a@ zJf66Tak!p0YrY~)$!VF~m&yH2CU+V;qUz=*c~GRWexjW4w1{2 zqkRp;JV&tf__dRN7p$5Ptx~#5=}(l>m-UL%wN~z6x^0Xo5=7cOeKnU-x_i(uPoLjS z(7oz)Z)2pC{mTjOyb-_tqT!vRSC@y&T)!!>l7wizv#fWPpLl0^S+F6PFg1h7B*0S` zqV)t6&e?lv(GQW~#qYuru7b^bkUq?2pC;U3@?ar7O|bF!tn9WURwZ77U4s34305N6 zRLy|7^^JKOP>dRQ)iSI(MVdzid;iufK4#qC1*^IRUw>9ubICy(r**{s*ktsr!fs!U z1s+=9p`QQ`yYLrcW=n;Pj~$0TAz0a22OE*&=ObzeGn?!a zk6Yqz71oo+6Ep08v-hpJt@Av$BO*YG_smAJrTGuxK-qoU?lwEA1NYR&L{Ts02ocKP&YGM&H z!+7cahILs+mu2)-meEF2MlKaxd4QBsAcPWh7q_tuuKk$mA>VQo{>7ydZ=TXG(6kcy z9=xepm|5(#wb>$t7c>_%Uj)r)QMRZ%Xs-@p-5_b(VW(P$5%r44f)*Y@bDmaj2$D>& z*t^2sO($P#(X*bp{`j=|buMLbrll2JTEXAY3O+rT(%{gR26fwH#^esD*Z3l4k-Zmd zc1+xxZ^0)A=Tb{jd7(mTC!mL(q(u}@bbdc!FQq9gT!3AG{RP1OWMy;> zl+FfSynxgoXfm}Ab1Kyl8`^=qlo{^#b|n2Lmrm91cP8Ea|w5@joD?Vj}C7|g**f4hvw&Hv`V)>T4O+w{e zr>_xcXpE=P=~H`Nzor$gr|x>{zT&ByE-qaNTF5?^MG1}O?nrEJWVG$=fMD`}ez@K!2IWE3u#w^PdzC7W-;R%2GnQO&*?jvC^ z&IIfrs7M`#XyVYFeLuD~q6^-2w-vmZO2$bb?8XJ@kx{(dtc`FcxA#{rAu^^G_0vRv zg!B-b-N|@Qb8W7Hclnd=YB~Z9H1;u#r1R=nheJ zgPP1jQh4hJd@XUocra~hT*^)TkcGUTLDe~^#EIqGPi0_7p~aeuHDAP<#Vj>i0NF;f z3JoEY3Yb;#L8Y-AJF4V^MUcu(g@OcneE3>|f-oe`TLeAxpiPe@P*?(m-w-JL;6dxT z4;#cFHjgSS1=7lZD7@7^YAF-0aVjVuOZP7M4?=vNsn0brW@2TKav&HY$orbyjBoTRF)KBNfBNo zMW9OCK9Zn^6A0}cs)o!A1=@%6&i&A3lkhF(@1M||TijdFRQ@F3b2al6ekp4*8Ld*6 zRqFDhQkRA$Hro>FFa(J`q4li*VUFE++gcpj&=NkVLQ{Pc-+oyGC0#ES{}b?)uwXf{ z3hkL$(^8jFWf@goWK=;MiYW%Oi44SegBlsYwIR(?6ShOL_X*AWmTY-@@qU4(dx>`& znTCrwi|A>r`3y9JWy#)`?EOWucP?$WO&Hj*gA7$@qX+cbM{Hw9+YTL12rqhf)|7wM zZd3lX2I44gdR`;`Q){4NOIy3NwZEaQ{lSKI?`T94Kr>}i_R6!RumO7SnzZ+xht@zu z7rqNk<=eRkRwO>wK*3DGD0~_;pJ7cWU#z)U^F^!~EKMsDSmT*7)D5EBfGx9)z$(gq z2%2#zce{OsZ>oWcW_;9cmkcgJDYsaYo`EJm&KUYq-=fU1#6U|7^eQnBMQ20Zfie%9u|8p9-Giv6{CAl?fhGFvi7KmszoM0*E z#bXlvz_Ix)g3olJbD{HP=*$Vut#6>-+PrM;(3E%Jx{>2%Dso74pmO0mm(9Fzx$uoQ zZTQTpeMcu|rbN(r^X4^2;ejIPJ357R=?<3e;AOgl=yMlTL4p!Q3q#huKrfQby^qZg zr5#Mg&s}s1-tNpzZG@A|1n+*!V$Gu<-R zN@%TwUbGV0BFf)xmxI&rGrO$xfAlkyfiqwu>hh^V+>dYl;j zPW%Kq)5zD{x#rFn&7In7DD4EJS^lwz)lFvvLbkGbqUM3llq+}2UGCI!GxH!>ML(l+ zChoDsiF4;u=q#Dbin6RIFS4QpQVi4%(zgmC)07e{;LN2)>}YbBJMVPa=dAO@8&;Go zX5|w)g;^EZPDJP91kA55+k#}iB=1Y|{wm3P3k>#}z&wp&EfrcH23w2LF^q>E<4$`E zHn_u`w>+F_`bi>0#33OPc$%>GNpvdX67Ven--`r%n440?0Bf6pgzr$R?BIiX% zK;Q1QgkJ7sVCGf8cZ)k`u->Pw5SfXi@D+HYJ2KVRAyvPkF=SI9lOOLV0JkGUxFu|u_Du+gky=$n%trPF(EmHgn_FOS_Q;vWJ9B1Lrb;PW24 zKM?ov7e-B;F-HrX3!Se)=iZPu&mF|)kwv;fNLI+=slJUZ{3v%mKxba)Rz#+Ue}sKm z5#|!CdRFh4Jsw2A1xu&6t{$V+WAqz6Mo&L>i)%L;2I{k}K1?9946tUsNXsbw*zV}Q z`SbeNR5}l^k8Ld9rc)H;#iff&e}hY(25fibma%~hZqu#3Lsj2l z#8!k*YxYC=@ERAsD>Bk@`~Ay__E|n3n8oG1#-ks}=f50EDMhTT>2yt}FPcs{i>6|Q zoW)17?FNne252#8FDaw7qv*U75r3uATh=q<$PXEVTVZpzVrS9mGrhZIQv8DEg61zk z^JzNuXwEbWv@+L8U1x{A7U+SIeKc&xI_xK%-ig5d1K1k_tE$OI!h%H#23})9yK`|l_+yk<;3MQ$I4O`1YxeFR^^+)#ri{Aljn1b(h zyk1O-7xFj@u>N?%^p#F!^AYJE^cu#QYvh5*F+Mx`i3D`#~ zVZEVF(o&2+7`7yq!fE9+hJ6g!uN$W8N_e#_#9Yo0Cw(xEr~{GVD0+di_@%CK46K-3B(*8%&eZJ1e$V-4IBu#fb=x9l{U>7NAq ztj=Ogc-BhzDZu8+!(MsVzmtdkG{epghuOUiLu&<53TV0y(AG7vW*L5TV7*t!^iR=Y zTA05BmPpABi)dP>+Kj@4n^bckzb9wX!o$gvZ%{9-`KltNS@7KpJvk9;3%(~9}r>-;3 zTkO{6VP*>URRmf^gB;sT?(H)AfuN+kAU&E+{jD?RZ#oqV{|I|fPML_sJWH^okEhcw z4x41l6)?C027e`B@af^S4%aqz1y2f)*+UW894cGIN_*7(K%jPBu-vV1n(D&0{qWy- zEfQMZ_4*}rR+N^Tc2#}`ujR48@QYbhQp+l$SVa`SQbh4IUb7^U4TLBnAl)2l84kqF z2M;U*59kZ8czqyO!Z!ip-*`zhXBfUoZb87{w66dbYn107yD#PrNZh?LUbN+ z{$S7hEttil(0c5y$L?=Dc7K3Q9o3bIfw$IY{r(1(_YDe*)d|o2$c=Og7B2b-owu(r ziTaV?i>Wr%QR1he6CVo)zoU~BS98p2j(JscjF?obQGx5VdTn=T`{tlpOK&B;jYH2` z^2g}pTlw0KqVFCVLN7tHJLW`mK5qK{hRz7%wJ2JPqF-4Q{eV07G8#+UV5=&#PuQT@ zKEv?$CS&%9${}>l7XG{W+EbJ7H_)l9@qQyEoblT1qUAhv{=g9P4V_LBi#r#0zKA)JPh=8ad-!ij6|!7Yv;QDd zL)9@&PLt*8(K{VkNiORT<_)fe-szL;7gw&o2CyMPpBXl*B8 z-=sx`>0#Eq56yoC+?R|G!O*Oqh~g@F;vMDjk@LF%A%t}iWpiMIK?aWcp>wB&Guf`deJ)H)87Ph6F>cN7SdIqjx&FJ=qNM>Py4ItCk_ z$DBX8aeiY?a>`ujT$OOl|o56rZ8+4K1H|U&UWTv}7`S;Ui1m zL!cGao1m3%Lavh($~Ez>iT5`q-iJY3CZ|YuP$ve>9kg8qs$ulRB6+6y<&9|-ZwW|8 zCV4jh8YD&~)BjQZ^57i&NRXJjtmebjeE6#7Lv(Ia#sC{^pk4`r8bOR!=cK)~{~V>} z1+RX-NIC3f(u{~tvtKES#qfDH+=m3D6kle)W%hfK+0UtE_OU^$IzSsv2yy#UQ?*27%K%51s;0H8IVX_cJeOAZe9T|V$)>9He^JQ6BmWAK2EId5vwoc}$ z10*v**#&B#!ltg#=OnRtH(&|(P)@X4Muvlv77sE1P<%_VkiA&=X{Ds)_DRbRz-ltB zo0fIc@*6iT4+GXm5J%lZ{xm?h%^{r~I&Womn`m^u2>b`Ia$N-Wiyi@%3Hh^>6s@Rw zaeJ1URBkK4KVpfvNZJyBmjL|#BmnnGWe|0!)(y0iLsn&&JH1w|t%RQfEM4n3+y&tB z9<%%3fYq?_*&=MkQkdQd?m1G@BikyY;9}Utu)o2ucliXJylH{dv1`2?5Ot2dKEkIc zkG|dC7rb*RT?^pcp&1uG;L@mXi6z$`MlchJD~aPraQA} ztQ~aipue$$-s9kns&l46^xe788$z4A`$%)Jb62DLk4AT7%6kIQzvLms!wv{TET4Mr zE)JEV@x1KKhyF$_*4@jxdwJE}i(?m63^3#l8eJf^S%A4=jXhJo+@H4a2b$Nf(j?vw zW4@CnJAKsYTNE+*hY#>EA?WtS=#L;2v4RVl3z{#2W~8EtJK$^;l(a$}>dEK>PKnvOZOw{;6`uK)cbjW}Cpa4F;{@ zkXRkIjU~x!)w{Bp>@$RW?7%q0R^bpmbHpy@8q%IMQuQm^+Xhy6k3m0H1_H2*^P8)=eT ze4K-tBdd`;QJ{U`>m-XT5on1(FA{-L`*MV4 zrs>Z7DFPKSCl7jF_DQju$oyf2-%AY_G#4~q1kH)1m|Fr@Y@iwmbqYc4I6F~Hp*RIi zzF~UjJUlD2-SzPKbz&ZF@x(^KJI2{>n`Z8GaPjsr?WfFdGNNijR?~AaduRPP&5eDHc7cl)l<;)i(OAiC>J^i@{9f6`{N{x zFd{QT`DxbnyVB!--krGkBF;seFCtEku1!QCww|DkHb~_S+NQqQF5AZa{q;L>mJ3}a zPSe9>GZ2x#bnxoiNc+U%6~fy}&<}KmTG|TiTY-JQ5!iRfSR12gZjE7P4$u+}GN=G+ zj8Yp$&{=d|A8XAod|+@7%-n-3|Dw|+&7J&t-46Hk*Z)9gxX_BIUJ=zVim0x07T;Wf z%f56nPDodRt~tqQ3$jy(VH`IsL6(O`THQCiuO4?Rj%H5-=R-ZbnJesIg&n*q?0{R% zZ8ipTEufAKLU;gn#LONTe(DcJ%0;ddryhQ9DoNr;Wtr{e^+eA+KeY!qp!!}`RC?H$kO3cv)pOR|Lu0nGU5W4UIYlam2 zS|uoM>ge&b_^!LE1i!7DjFh?34p!R1tI`fiJ&G%ESVr?H+`Tgrp>pCV^^Y z%zA33HM{!9`3IT@zbLB6pE(Tyz%Mmm~zod7i+HOpWr?KWE&@`2@s*P5)(Tl2$dW#x6VUmvx z6xkuIJIpM#pv^Jy+`8#kD?VxW9`J!_Z_g?Eavhd}+%I zDR2LaPl9LM?yl!=XJUH}gXtP<*I@gi!PdpX*$vtZ*<-vIA|*ju&FW(dwX-{?T!}rP zi{ZN`{@Y+HQT(eMgsLfuuiQCZd}Rf#te{tA1(iA3r!%1K#-L^sLVSYv+OS0BZJbKj z+iMiAQ~04)Xcp91O6^i=U!>ILHoWaIUML~0JyF443M>m`*Cj7~oK~w~lo;T3m4!`^XO^#T(v@4hPRk^f=)pcwW zHunJSTZJYpV9E{KoLc4FCrWvD%l-?RriXS~RSErM%@XmZ!n`yxn#)_4*@}!_k#Dl9R{S`{e`FHiR77q1(t_la%tDjW2F&phm}DAxFlpAan$@Zk?>7)jW03xkK|xY0)1pJt{47 zPyO&C6gSb}m)3X93o4pLu?lj3{}1w5*So-}z{H7_iQJLSCJKSURYV z35_>~ZB|8_Q#U@9HFOWd9yWHO+UM}=Nn*<4`YeX^^Fk8uGV`+gExX@u*!>;`EK8|9 zqyd@`C`UkK44BO~F`uQ%sdAOufaMDvWt zm#qj|g+BJ)qqM$5bHY}9W+|AnofeXAZL3GnGz!*__@P3?;%LH8+g5K|8NP3;tct!) zwb!ZkZ=7mBKKx1!X0zQ!-$1!-kTwcz6qcSyR8G|)?SQ@hiy9X^st_~{`QXyxEF5C~ zJitC8FY%unnZ>1xOP|f94+B z_TVg;vSTwt*164nU*63Hr9Rb3UcG z*p;x{KY%@wmpHwAj>MQ6%IWenhJ9cpHuVMA1=#;Dz}A@F+90SK?s_mQoP*O_ zH$CV1&0E1KcG%skZ)@uZ!&;CQH7U;;iT(CS{Nn@1so*k0EHlJ!m?0h>iBl_k4}->g zoQknSvnbFg2N!K)_7giST@c?_)N2fT;9hd^A|E&5#Y=INK>Q!>us`gEZec4jkr~4YPwgAZV)yCh+U~_Ytv7R#BU5s*N?~jqDLdKQG7if zH`HL{c-D{WBNwW{f(x(C zdn3#@XiAEIeBf9V4k?-XN;8BOk>w9w{@~y62j3$kaX61wplY3BW42DU7w%K>( zm%ylWnVToaiCddDE|sg{pBnGMz2CUhO+NQh3nSGac^;QOa8fQ>WZkW8>q&Gj*q+%HWEldgC^ds$!;e&(VRvXqzhfm6HVm@;Yr>r)|G;+I9~#i831!%u)nYqe3()u$8LPsHD+}BR0AqU-0^+%-;v! zp{Wrc;*f=^OEUT^p()}k#eSvOzbeIk%QCZ21FxfjZgYb=NkQ7yscpG6ZYQC6<4fgO zx82RL_Vr6evXH#E)X)pBfp!hFFB)jE;=rf=O5R<`yRS;#McTA&LSTjnnk68~2XLYE z(b%+|vmDraSK&XQ$;Z&-H2&%aN)6&C7EC;_Yibl-1MM1UUo_B8>FV4%6pq}xUl1}l zp|}0RGj&+-DQK1pUWcY$>nED24~ne2Y)`V9gS&s7y~AXdjV*lx5v^uG`LEx$V5eazHUR zY&`(2OwchlXn_OT)-9#yz<$bdKyvFIrCjvL-frdV=ZQOW!6?rgX#G4iSEVV)Nt>+lpRZk7HbhCgd4+mOvM*WO1A=!O;Pqeoey2+Y9QvCvx ze=EY|KkS`dZfnU3g-3)06j0#V)bIRDaoRjQhXIsv7Ka?z4vfr1WVDYV8HFwp# zQ#Dgfm{Jd*NDah-A-oh|oy1g4YCcspdA%lYzBT`1IWQ#oTs1Ky-U1_@v^=?g#rdtF zO~$yTxuy9cX_lFTOI7gJ63A>0F=hqlwoXCVb)GWnslMNQ9al}hpk30zTT?MdTqm>~ zhAHC{$3W?fgAp{z1`Hu8F-MB-OMmv;<|Yo3QY%sWi=W>hMJEJu>O9 z%FKuE_C+CykABvC;qWM)7byCJOeMlERg;NAw}*CnXkX-^wPX0&_#Xc7XFqF7h#ybQtZN2Dh)1aS^w1ROK6&~Z$d*Zc z^G7y+myMt5-M4l_@kvo`iKnS*bukz41Q>sIr9O!VccDXc3p;U8&A zCdg**rhX7GW5Hf~}HNa-ib)iXUo-3Mu)7;J% zO@{!??DW>W{tJ`l?8bPAA9;+jcYg@<{i*3}c?WLq!0rE3;I>Q~8L7jp+(D8v6!U;W zc}iX;IyyJD^_%#2zUc7-)Wniq+uSf?$E?rG9K3I={nq9NGVR&Wo(=uRZ0KPwW|ca_ z#stqeL3$qGi5alyI{9qc$Jr8l%bmb~btjf&P z;@uMer&{77E&Jjo4C}TMkye;lWANg+QLeeS6BpXNKz)3}HP0833mpZlxa4bYzG}{k zZ_6*V=7tNWU0`>C{fz?qgYlAa3Z~gWs{}~K3Kfe&nmtph?x81~3_nojYL1V>1&NeD zl$n(%CrXl^_E^1NO20i;Q9SK+>0X!q#=7+3$7&Jt(H4hj)&%0K_f06U#!4(Hx1bXt z4nGmBz29~JDOg2GpTU}8;#t$tJovFv`oLpV7&nf3ujl9Ni%({?g^w`zVnK+7b$Cq{c>^q-m- zS?$^9g81n&B+<$$Yh6HxR41!ro;gc<6KuL&Oa1s_)Pv)?L|q)Qb2i%~$btR-r9$WzE@G-5i}{PIO^S6DoBJ&1|n)pl=8 zB00bIjubuZz=s|9@T$OvG~Cg-KqPUHUI&yh8G4c4Cl(v++>DoRLO9=~dB`lvr1|_C(sPNaS8Shqy zFVkF6zWVMnTJqqxh0K%M-1~goZ|~A%Der0Sp633>H22{)Hxl9)o*}Rnkm(J4M246h zo7Up_j2)lfSo1e8zcnuDU|*^^xqPtZbK)RMiq9J)-M8a^6Rc;8T}yW@{f%1suwcb{ z3zQ0O;UKeg2y6(sMs8dzw{#*>=}oYA_ND0}NAJ=s{)umt&2mU~ds_2*AJy>9+{@W) zW3D&m`bC&)p;B|92E&{|LNe5m7)G8^I4RF@&K3Bt>F=+#R4(ZV*qIgeDEIC>S}XiA!6HmIx!qN78o6(BCILkf*Jw|${HEjK`o_tv&a6^=9=ZiV(9X$T59)?U%u8-T6x>s7PxJJzhMh}xR$me zC1va2)B+?*hZ4<~siCiXY-TyPl+g>{6l}tGklCN_(v`Mk*LSJ7L<&mJtEKljW%{RJ zBO~VhEZxu27d=a7%^p|{3ioyVLIrB61YN1jrp3LTK&!l=JB4m3Q{#e14to~DE2+T< zO+CfaawL9WGWw!SLR3y0R=;8OFM`$6T7V{2SdMxSa)T(GVVJNDNuJV)h?jq)d3(>I z7djl~qSMD>R5J>%6W9DSX+E-NVcIv|`^NiaH{Qr4<&F@EaD{L;@YW|3taDaL+)h70 z<(|pta5m&_dd-mt%o>)GKC5azwr7dh4ef4dU)0b#vSw}*hW8HAdO+!epj%S1tR?HY zs%aOw39Fa5;DMcJVe;wIHFri941L~H^C4?)r0q`F?t~Y)6S5X+i7Mdeb-CsXRKW&O zJ!a$~jnBE}?FZJ}qmxlozA}r6u>Tc?{STyxRIy;{Fv{p4B?h>#gAE^xBQ%1}nQ;A*ZZ10|-s#w1U!W=FPjg#d zKP5fQg!@p{MB_ai+QXq24TthwC)7bVw%>)odS@KFv#)Ddp$&vyT)_&a|JJ`>FY&r{;8SEtEjLRuHKJf|0-^ zv5U50md;A^_Sn`heBibfu|(G?kQ1vQvp!9lk32P1XkV`E%az}_T=_xOteB~G%U~P` z;yIv%2~e9e^-8FGx}UwbQ8`?8YLZXxy_I7qivB!{&?C|$rlQqF{(@de|;aZ{S{j`#c8&=SX|w`NL8|A1(p)X+Zm*0k+; z-=6mudEQw@o-z_ln=3V+49W}z8Y%K9)bg36-#2OAcJHYlgEiA1hhombglMmAXi+!w zb~A5Z#k_5ahp(_fExOK8T7|Gtp`>A><(4{~3w*dIP0@FI-`A=cny)zO%<7c^58*d>2tSZ!iQZ>x8EO#%8DiiIOij&tV`Z!TR6|R6KM5ZXmM6(Q z`0CS3LeA($Pm|{T)RnJ}16AB`+YPt<6}asWlxey4WKvtxFDjaxNliOL3rQdiGkB$dp`}=! zH3go!JE6PDM{&WUyAvVz>wwnTNtA4oob282vv{Uf-%FCdqrPx!0O6T5Hy5wR>Zj zTnY&131u1sk5rox4lDhnH1ELQ?cK=tO`3GgIMR$cEVDlEt@%jR)I@uCvUevh+MR@T z6>Swp%LbCPfJbS-Y0Qk_-RdbQ3B`r(nSl;bUiuHX>z#4nDZ5A3=QXsC>`pkverxWx z=8N8%Bs{G7fLgtQ6t7TPGN|M|I#*>mE6qD^&A+TQ%_M!I>`6jn#`G*{K0?_uO55GO z-R-Y(x2tH%Lnlmf1VI$2y*Eh0*~UzZ>vdL|x83b}JfT%G`IJrXfs_)xb_`@ldwH^# zCofu_t@Bo~P61ES&@+z$16s-abR$BP_S&9n|rB)-2j9YwCo6GC_4$o{-j zYQp=2Ai^)t&4n%7lb}5bdetPT&Dm#jUC`+DMFzpuAtFd3VTp5-Ak~{L+O%A>N3H|U zDA$WkS|LTaK2LMF6VcsS5Ybn4sygn=uzeZ!qRTKQr4eZWQ%NAI31VgDCbWV=RO4K_ zpW6GZ=dZQXE_~3|=4INwsuM+G{UuNH>k;11_xn~mT_VS(9c7gI3?Bnns= z3s5>bl*%bJl3DbWE$Cz1^EY*-HLd-wPDPP?^|?E9vM_q>Jcz@$_h5SuUgSNP8D|bf zD9s7P#>y%pg*K+iEUetlJv!~C&plm~4xyKkB=LtdiI5`#L!U;yB)Y%iB>vjg3JUH= z=YDj)=+QX~)8N@aOBl!;6@n8&$~BGDlgT)R3DSH=og|lZmEqK7zQ)c|+ zbkC+9N%eX6VfS0wFUnjkEp6Vx<{i9>chGaw(VQWQ5{O`jsHMYji#B{_o2Q7hi_dja znrQ*052Q&7s{KGcsN|?xqf{2<2_Ri3jcjO(yy=2r|#1Y|8PpWZd%&EhCxihITi!ztPY> zoQ&HFd2cNNu7WDX3?g+0PCi>Nsn2mL6J^2MZ?8Q6Me=v8X>8_=}QA-~e?252PGVr1XA`uXC4UZ)I9Q+o@@KnL3e?fg;1dI4)NO(W< zG*V^D8c%C}?W|zKJ#FOsM!vra`L2eN13Oek2N`WZP?`|4P^!YH0sr7tczYUL8>`;tqJCA(mmxU z`P}x!FNtpo_V_GYH93Ebc$YI*)N{sX3D)i#<-hg5jI>j9cZ%+>r06~@SZkx%^aRno zf-DfVw@FaLS`;*vb5UeVus87V|5Vt6ydxzG`Cw3+s~MWc^91|IbV<;+V7FlZQ-Wo0 zwNj0x(6Wxv9Ll7CEa*~7mwGM?`>tTujrY+w7*#&siITWyNzdEVJn&dG^F3VJ!=>LC zF8$z4^ndJKO_J+6uUiqTNbx_rku7QeOL*nnbJKmheUdokynF-AJv0gw0Rpn*N)ZMt zbAT+pLA6Gp3k_Pm+DgX`(c&VHW?$NI?8;W>a6_hPs1)+_)2Q^ZC-7$^5h=OMNTL}@ z^o~fPmuFw}%87Hpi5%VlQb&P?1-W#Z!KLevdfqJo64kjs|tH@rqRYkAn+Aorbu<)S-r3)h-5|3an~ zFBo~AiT5SaEIuWfDapJ;l6m3*T1%-5){QEcEkbM)N;5hjHr6Fj>p1EZynp(ldEq^^ zGz;=gEj1TG3Ey=J>MNva$Dv6cRAvmyj6r!v49d$7(6Ow=3ME*n3bL#U+3SGr6*1eo zC>}eA$w#|f+UL^Zg}B%KD>$8zZ} zhAo0=Gw^x_UcVvm`end2w8a$-f^~pwPKTw2K@P`W`xZrg%qn=la_O%@yIX~d-jY?E zgU}EuPGeX;4A>HGIyb*_^ZSm?@5_K)ZH=V`fpKo@rB*hVuK<RXWPJ66AMrQt;eOZVnG$%CQ0nL}Gbj!omQ4)mH zL0a819To+y?5#=BQ4X{-T><+*sgX;;-+)yv@^#my>asOO*?F#qSE!UGl};-C6qU9t zbxkhN7FCed2o_TY5VEkdVIPVV6P**CA3`T?)l5|k7SDAv@-AC5Q^HuArU>Tn1A-}E&>lD(m@l~F zaF9g%9+WL)yqWAz8)+Y3e*ZjI!y-D@xpSTSmUZqE#F?n0_e5ye86;bSDn7sxt&ubw zM-J2Yf_{;^M&4Ul@K0ze^GzC66A^L2^A@*{eSyEAi54=SoAbH(q30%#q8MY_{N&i6 zDNxs@;EYYXM=5p;n)zqX^VjDl|4~W*3(X{va$`-x6t|>AIt!ambpijXWhy0o)-ugn zrVrIJRjOsIC1Dv|Kx#qAEjnAPN-Wws^Pv}Kd8ByW3J?E_&T!4Iygc?Q2QD> zDJD86IzNU^Q(GIw3Z3(MpVlE)QxGK1s#$G0#GQryG%x)XoxXeS5>ATWxO3~#=P=8& z=Gv#w`KzhBsOU8PP1D~yOn*na=-M>`NKc70RgeNV!_ z9Wg(+la%N?I!l=GiFP5v#~Y#F=tO6lE1|g(`p`;x=WhJiB2SLb|ne&W^Hmrfy!VAcx=)dJy( z(6QlSrLW~kzR4Av_fE#-qH>{~>+3K_y_xv_39!~AI*~aapQij~PID_WlW1lVy(5$8 z3Fbs=u?Q(Fi3E~sg{;be+s-sfZ=)abBB);Yj@l_-O@=?wDS_X1LMcM&%6J|+@db2B z(k#}W#rkh4)_($>vVn8a4rJ>JQWt};A|SnMxRQD~q;@`o&OPo-q;L5MM977#q@R|I z`xJNna@iVNnLDAm6Z+6j2$#MR)dXMAK!Pe{s|~ix6s*2x*x||c5qIu-;EUi_ISXNM zZneK>I)$EicmDRkv*UExPM7VcT(*hZ@g_lUvAsKO+1{NiAO{mK1ILk2`Rlt=?|2dZ z%AK)kC$}Kne|&uDj34$QkWkKz?cCUYXk&|&B62K1T4lSsR;aBGh%U@4r7y=$JJs$c zfBl2b9knyjB)=|Hh@#-NQt32wKBK4n;?6*l>9U5xzU^!YOA3*kH`%^~PPd%z&iU^A)VtGdsgiw#RZ0U{eZV$kLez}K zc&y|H3buK(8kGBr%6`9@q1l&H$V*XUN{rJg9v)-!XVh15WuA}D`RIJdqx0p|OjMMG z#UOo)x!rC(m)sQ5Y|P3LB**Ltem9%%3fQs}a~mFx-xfvYCE0}iG&+6FcpFZWPA8py zh)x&EkwXv~Qv)etP@@rWPt%%Oy&mY;zS61QiRZgMMfVz$lr!x%?3$I3LIwG(#w2@e zyZzZdNKT2<6F)ui@9@OGOs8W*CU%8ZhJXk&EX4wBts|qWiX94}z8T@~%)hu7LTyF# zb^~f25y+Z&R>j#X{k{=m)37iN3-2&2ybjp1s7I}^jIH8qSsE(iX*xy zEq4IB$FNQt#r_LexAcfi@zXj9A2aN)ng>ymsl!Yi<{diB%Yf~;RVtJfWH5tJFR-u* zm}pqgvdVgF{~H&|2Y}@rXM-t4xg}P+7LB5QB4A(WBxEW%8Fn)4{}jWb(jp=YbY2pq zb%u%+q2Q3UEY!zAlYLyuoz~y$8ex&jdq?Wn%Yd~}YHmkuhOL8mUm)2SiU+0jtnFA;;bXwcE?@(T>g^3n zD4ZG?XQu4RL&*LTU1K|vpCmg;_8lbq#ARDqv5&e%19EN&WOdsxtpdfk(He-Q9-V*n z;rzSf|20;W8#=dx)9aQ=PNUPu*!<~XVpJEMfekaT;SGTeFVkrgY{QKJ%c3BmD+DfE zxkR;C%F=l~7J&2wV9Oq0Df259+qq=HKtFH(<->q2$?20zCzrm1OJARVr8GAWXh{V` zN5W#Huz8(&chcGqXgIPJ0;9b!{}Pegw-OjZXT)IM8-V#0j=dK3KN^7LzbsoM9j8-x zI)&fj6niYrRABND4zuw3~502~+HQEW6zmRsH?1gB24HbApf((AQyFqYQ2b z7Qk{LyIZ^ePh{_oO*sE_s{IL1!f;DNLO<__^@(V+Unk~5h||Y3eN6B0F+DN=uDr>X z3+QbX_O_HIj-fLzdY?}5PxgovayPxrwJ@3Y9P+MAx=z^aT&x#K~4s%J;*Q_D{^y6Xk1ngrP-+@x*wR z*U%{zlRGDOeuz7V)Xt+R4AHvP2CuO6u7G1jjN*g!z&-hM=#(8TCXF-y6WSXl#a+*f zXL(|>{l%SI8sa>unI|>xIH`GJvTZ(^Y9RFP462Qreqr zqkNAxLl1OUEqGdZ(u>^5Wts)2S@0cZ!6(p}fvc~XKs5zq+W4m7K8#==w zT1ntsLsrQqdLZy#E=4Zo{=1VdY`@V-h=$)gO0{^JshtSV$H(G7O$!u`iPIW5t%2{b z20j7LRu{=E2qm|xH6?`bicnXtQMj+89xwsQrPw1+5njZ9!!w=DzL6)%R!3pwM07rp z3;K&Z5o5N+%(j?MwZ$Y-YXc4H;sUaCgIrgJu`EQZ%UF-Z3|`UsAQzM_vO}JpOn&p! zM^Pp$ETc*?+bh&fgM5aa$} zs~6VYCMTu*7J;PdXcn1x7B=EW3v-%2~epN!0}<-0d`_^NHw`pGI6P=scB_sib^LN$G8+ zQ60)s2gq1sOXlrBC2Ka*R{fBYqWZ@I^jB!+Zo!&T3A!zVG_Vw9_s>GpuD#-uH79F+ zf;DsP!F45YjR7LVVbL&H(^rZnh1LW2+y6lGE^8LN=w1dddCJYcr_LOtL3SE6k7w{A z3Fp*MriSt%4P^vswkBX$48$lQdQ)IV7h7`VDhHu?ulP_ef`2Yqen4{z5&f10h+Yzf zPBRC+G|&qA9BAi2`=Nn0+mem@CThwSu3Hk)X{(x0$!@E!d~~3_56z7=ck~n8@`t`y z(~1-&%+utPmspc%ma5HCwNI6*)#eLU@@+v|K#DdV`eA4i&8UPKmGF+JgeSz4x)Q6BLZPy3tZ7hF9H_~#=33Wr zE;NO9@5B_fFn>W)qew*XY0!N9*8H72?=lD4InaJ=pv^^-bOCGyw<4Dgi{c6*)N6}j zz4f!9xz~~=86;oOv@BFCP83gGU`@=RoY0)m{0uZ(m#RJnRHm(7UmUX2fTe|na1%Lp zgR-&aeKQd6CX=YJ#5eK8N@_5Dbf87!G8;!{i%Vk&+S@`sN1Wh;%L=W=*qcIhdA%4_OXqjn2gfSi2@rcY$0uU>z&D zEn`(blu4p~DR%<+^xF8aBc6Cfq1#*2NlRh2!lxxrKaqLx)81Z+1paSCQ2!r$-+COm z?*kbTssIqr$%drJ{6n~sfBxIMUhRxEC*N#c@ryEOferLyVe|htY(Aa9H-})P(;iGx zK}xAmdmVt=U`NM^^V~c48;CtRcRHn)57E18l7ttH%QE91cP9PO`%5V+<921-{#zNh z9hH=HK&_KNaBC1v2)a`x)skn|x&Cet`zv7c(0*;I_URyVXLH(9JTEJGcYezZH@BG{xy{51 zerg#c3|aERgX!ZZ@fVpn9W=*F*V~lvieLTVc^QUU3s@Zl6U*`D8(MF8XL?lWUtUyXg&=F z?pW=d*v^UR<6V$@=k0q`@XMHCpR<&WLy6>VNBqa@SD$(P@;5XNtiOX+baxgkugmhf z{Djx#`S)*fBQt`eFp#DOnKYngl{Q;p+~Oo?;}`aic7{gHUlfu+SDV$gDloI-UQ&p#KZZf8XfiS&yu zFpN^z{JNR>xH9yQCD6WyT3g$-wf%{$?KhxF)~2aAIO{H1z_NpMgCxu;&3K+kq1PMo zdo#;lp&2(i(AZ1RFSSYhEmKmsT!k{@a!wL)4#!!CQzK0clNu>`^hTuY#}1bWdDXrd@_ zcW8q*5bX-VMfY5lB7{t%osc2CK~wY|)l@n(x=6U;C)MAqb?1E$Ri5+cyF?tO%txOFs)6IFz7$kh9C z1HSRWepZc(d@@ZI4e=|h2u};%ljF@ZvyPhUsQHScCJ|G$(x6k_U$f!R7&pjTYRNj2 z=#<=m@;zbxZ^-0$XQE$_87%aHOmUVhh~=`QraWHHew~@SnQigR#WP>TGyBYFY#mIS z?4FYjl}ZI};ywjSrBgRe$_K8_!pG{_!Wkd0S;bV*P`Pe9OAnFxg=a>VD2rz!pA7fK~pPHhc>pi>Pvp@2l{l9QlOKr#law`)Au|TUyP+h4=^AUM!GgR<_ zJV^bp316(puXWpDo?cw9nx#)UtGVc^KwA}PFRDOmC}JZgY^6KMM2GAfK_TSfq)ysS zL6hH&CVzY8YPr$Dp;J^vKMAN|kd^T3mbQ;a=@)2b>{U+-nG2b(K_*5)a~n{%{hWfm zL5NmxnUX4dKjC&QGVR7k$P_33$iY<$LJyYfkonBeES~G0vhFD_x~GJcR!8Z8tq_P= zK+}$3wdR&RBhLx<3O~>wXx`}1zG-2<$lX)8DE&VzC;an0tGWu%Rsq_N6rg=$YV!1k zVF5Y=L1H4*unI*cGHSS=6CsrH$iEqf>G7iBzfesNQP;Pov5TnYGjeyKTp?a7#Op;N zUPhgVNrRbEK}Hs+H4$nWZM{VHaZ0&Yqt*yE`i#T4l1$qXW{MIb7 zxaQ)TFX5WGMU;(U8+$=0YKJw{Lpf0>$Aj7;>!PL#5u zFIV*CtD-NPnMxZBSaa|0-SfLTDwu3iw&tVexiyg9=+T4ra6wy8=`)Z-HABP{FN5Y2 z3tGz+dayzdUKM)KYxiw-0i3zP9;F4XXF#VBv$=J`auS((-&t+PLsOCLmj!JmspN(6 zde1Cqon%3CLGwk>oL;$a_96O^u9V zdEr^}8NmVi5*#eS!HWb3!>|l<1I~yzi1^X+S5S($6b-t{i&F6MgSLDzim8~Xt|#q!(!S_P z+c)ifVu#xHTw2NsF-pJ|H9V<@%~M7()%O?cU*TDfB?oVl@?&r&6KRlMM>d~Gb1x>b zoMOu<_7hIAZwU1WY4qv>GIS5WoDFJAg0cB%JT$SMh337xroE|wj#jj9(!5`wiR^pb z!YiREB(~`0qMI+Gn^R{iJu8gn43g1z4@!d)Ga4gpL(W2z@7SyVgXWRsAcXwmO{-Z5 z5$(e0gU1nje?U_`S3S|HCwf&qQ73GpQ^G8`Cm+-Xjm;r?rD+*e^wf@4?M8Prw6;4> z4m+w-(?3#4G}x4bE)?oL^Po*$A$u!i?^Pjt60%3rDoEd_W)+4ENeFGpEIzxR3Jm&C z`}`G}ei*VRUidfX39AX~b&=6eXlN;%SIEH%Ie1aXLFS}tVfQ z^mAKUyDM+EoAOPMre?6or}HGps3g;M&XZ@RrjxI!xu)ierY4oPO=$+rdxAJOh&?{K za5n3zwvAKKv}$+jiR>+ZY>HylS z{G`nZt&a@~X+)#pSkFFa??Y4K#s|>cB?tP;)ZB%7tazP@_6e>jA}i%!r5wB}x->#dBlHs*p{HkQskMjIgb=JCWCG0#!kA)CwWjw|LGO>m-^`vKw=4%#Y-12{ik?ojJb(Vh92BNs11mQ1GtvC z#S|7fmC5%lz#jA&X*$t|cg02aqH89+YLVpfaF%|3{1()=BGHv(yOL}#PqKab@hiQ~ z!i3OeLl7?s$-DO~tkhx_BhDRV{2h;X7D;*lSdss91MgA>$3)DMm)%RBi=M_M09*pV zR|x=l+qRTBpzQ-ym?vZqfs954OV!ck6g1;TcXzxW3c=r@NoI_n;U-Kb9AV<+vNlh8 zj83NC;aMWcmk4l)0AD2nBnd5>8;m+CNKb*}vcqW;A3nN`v+!iR3(q{P+BGUgKDntX z3Y*AfH&fS#Pu=+X)TKaPNt!E3^CyxtpML629gV#e;2sRp8KG@8Kx@gFq}#-EHnjis z8~t^j`uo8B^3+ui`80343ppxXX5N14sjFq(OxMlyRX5X)+sqaM+Ny%67pSuB&lNpZNAhZaVj|po*9zv#a)sxsB zv(>LpVoF0>6LwA5e`>;-yU4HsS*n9*3RJELbu=9{=J4&@lQ?g9cOP8xR*s@nl!!h6 zt0qB(n6JB}KGUp3ML*f(Wm3w>?2i8KvaP@?2S-Kau76 zG+?tCs%`;oM2CIT2{AW?kUEE;*Rq`x_~wltS!ncV@ry|E3D~!Bn@HE~ksiyGzN#Kb zB4Yt|0rsB)Y(t67J%KWJnNkqM7z0RWsl)}no}I9Am#m81${}FgK4nT)#3ZuFb#~PA z78)x2=7(Kmb&=KQ$?E@M?^=?S$$9OH6rr~zc4MdQ{V(B0@>dtt_3=R^k#*^Trvw8g zhhs_S@w!Y2JJ+bA!zg>FAx?zg(qY?(ibtE$4wUEn1@R&exm5pB|6+T(;XlyaS-gSp(skHP@{9wpkOY&8D>imOU_+Hi2wNP*T$pGpikgrag0Lmy5)o8(Ot+ z{h|gcnR__=d93-$gSNP=yXLxUzU!{3U7fZ9ZDZN2+4r0YALfbsU1=S5k6^% z*w;Y!+LlVjm%FCL?zS}3(^&I)a@e;uP)4#Y3GI^5zDYvsvsv^;&`fqKc9{@!bf{B= z8xCpxkmA7fLJvmGa$)}1;C@GDN&G^Z!YReyZ?6oaNZpqNt2DpKcB(tHX{y(81pVukY)nkDvJc|Q@FuPlM+svKObxmfcZ ztf?X!jzYlE9TaVYmNTHLaHdGZn{CXln_&#~ZZ0l!dloiCB9*IBMF5t>mxJ#J>p+irfPETv1t4&(i|E zG-@uh<}z!(%dFX@Bc)fUqX;Or2Ca(#dZ}G$r%pK+nQ}3?Lz<;nxoO*tHC-~#L+0VQ zp!A~4tGT?I@A7I2#-wZ=NcU8D7J`<&!x+rY)}=-qMCPNW-v1%<-r>YV?S@Qcv%=2j z$qimWX39F8ti#E>4kvR%RTBqP?x36o5j`L}#pW5DeDpPIkCB-dx%ZmY{g2?rnNnD@ z;CULo7m#VV=FBx`zH83ha+Jx;pnVVQ;{BQ_T!3b+Th_)~J$5)L7kUsqay@CvUC#;m zmlcpI1_>594Vj0t^m1qMC7xa4**A%2b8J(E8LT^ldLU$Bg}JE^O>Taq-sl>~^{9`m z>_O9ZM{HoeH?{nO%;Kq0G~CXLr7h2mn%|R0Brs%=<|57CAkCL^q@~R=lpWe=yE@1^ zv`z!Y^bKQnXFs+WDo-A{<{$IvH^8!)+zJHQ!kA0YSvk_>FqIN#L0KAvr9t=&4Z_QS zwJ;oA47MWIu-Xlxj14eVx|6vo9|CM#@S!rn@;+eI3Vk}qikWdFp_~TT=c1uM7}n5N zAKB_7`;|VjmjPRZ#*8+>u{6**H%J~8Iu@@qCvL~Ao)%B^w>x0(J&E@$=g$RiQD#kx zl4mtF{Ge0&yIw(rmJ55iuz$ye{W4(1H(_ZV(hGxbNKmZ{Y!c?)YKuH}k%=eTza6l5 z_P&l1_!%}-k_`=|@LAO=@w~h2dkMahhWldJ#jyV+hMm(ZRYPD40WDLYSqT_s9ZTD& z&0{lcJgio^&aimbdq#Lm2lGrUC9myBCo$~v68!HB%f*VXeel``|HeM}Wx$$qYLftK zeV<{qLgd__4foO7hUE1qU>}%8uQROOVOR?l`@F1{ND|GI)1JgXVA$_7>~6ftB@|pj z!QT)HzRs{^o9tRZB^>sSPRPv&df#la)D7pM;DtRe{wc%WvBOBZp{D>=Tm=U-)l& z-!IxFB8)IP&m{ALcBzy_u!~@Sg-F7p$ohE5|X&ubD8e3Ll%da%Hy!`f+f{L92NN|9r z?y)L;LifSZacnFH)WKK4>Vp8!t2)^5Prw?Q;?0Fx&_rB4PkZ|wS4beT<2tymgX?b` zTz~NR?V_SRI@H`_kG4@Dw=Ez?4NeInXGp^@J)&Mb1bz8 zq&es7Xkkc4av{X=ditf47jikogW|YQrrlC-h!-&TIr(r2vjj z!a7LWfsnu}GWDTDoZ`ZFB!Pw*<&n3xlR9t)1=K+5X1P_6MBFwNl#x zA$nENS}R1;32hqMwB8lxA!PEy4wrIayzrgZtPwlivKx$?GC9s0G@mOIzG?r`C3MZ1 zYtDSroZ0t$0x1T>HTNdp4ccrDrihG<_lB24$dn5|^S#_{^7TZ&-AybIHL{#0qkpCU zo?UhMUY76WKjnLIuf1STC{YY_szNv;&}^uM$E&3+<=;~N{kN2VKD$P%0=#*GW*Sr~2HiPX!g|?`9bV)j5993Z{!P@Ggl@{e z;QbPVe9s6jui!PFFOmLG{_WwwxB$BV`wM{m0W|CIuqFaD<_21FgPiJ6If-S66+b2< zl8Zeyr16FC%&Hbr=yO&LiK6OCr|oz1xQgDAG-N?@LGwM(?6H-h%HVBJ6m(&z84Mo5 zqm7j62V%3!1>;EsD91(aX#7-!%cob=R4Eg$LE7g)^9QGwZ)>E~L z6PZz>0>&QB+fbp^+(5fUV`>Gd9YSV4dCzj*@90)Uy_Fi870QegO`*qyL?NC_NVJ4R zZxRyqDYREK0dKqq+RL88D+9L5vQcFXJCG50mA&gj_3a)xc8@bj9B*<3D;6y7cp7Iu zKfQd%@?CS>*sjl5D%VXudvxmOlGo;1tH+4LJU zvB(!;ypkw!5jyQT`vPe)<{C8Dp!udj6Z@EbT2r?}87FKPd>nagcafxZ(_|kY4per z&RIYUO^8+#MxQ-4!7cMZDsH*3U-+S$%;dwP{cmU*T9on`G~}N9b6d@5)hVK9+U>;gX$tip&{P#)XU%oieAihsI-1~a3*$W_6F11(4MMku zmcxk-xjH#6^q4iv-RKfYv)dZTEI1swoVKBT37T1SvF2jUH?bxw*1Za8kH(y!ZBK!3 zHlYi5>Kjq#W3y&l=vfpz-C<2dkuS;8j#-G<{HzD9KUW<50Zm6;fnO`|>s^6g-CG@D zxG!fB6nlqiNj_%hX6MeX>*h)$5=C;Ne=je_k?=pDW9xaB!jUKp9akz zl#zXt(2|mfENCuhz6qMCPFY((&#i(+CWOxhjV4v`y2&_pJjshbmK^MF+CQNwMe|F7 ztx39i!P8RTUzs&cR)p<}uzg#EZI4+?6@l6IaA}pXYiJEP>lQvDa65E75xn5zyJlYK z4r_`P&Koq5xj5aguYU=eKd^*-gJ$llsC7G8x05&BPCR&G%>i>10Bo+C5vN@yiq(3CARQ3eo>0NuPpxGE?Y7cz?y zht%yt7kV0TaQ8hM%wM)Z97WO2d(XZE&CnJ6zJlN175qMW;%vPG*`6a^af8-d2Un@O zb<M zul#Eh6q04tD!f#y@PF)mZEEbwvgKUv?+%FXjPL+@9+@d6G&Fsi%bPzB)$y^t%i2|? zLO!*5 z2;;Ga&JCV7*q{qMZO4BS$m}2J+{*tf$dvu8hb_^4RS?my=%gs3InOBbjPjy03dXp^ z^T66`+Z1~QmAOFSaI)2h#UbP7hRz!nlnXj_7o92P%hOiXg}BgZx*($a)hFMcwn$ce>~^)zh|(fxeA z?~7;pW%r%5(4>W4K?{`?Ll#`1XjV`ofyT7J+H80&3%7CTm}34OH}c!r8M}ARKvMfi zjK1`~8)c!>684DhTT#BFGaPNs&N(|@G&{Wn_u&q%tAf^5p?NES9y;1sHOe6s!iLTp zr_Q(tg!a&>h+ki}NTxw)r}@MlB5l9#oy0RYdgeyIEH_#)hSwEFXayaJkiIO?bg+$e zbj(9eu`RLv_TK5cwSK|=#g3Bc9wNm~9Gy>*Le4%rH)rSOi#j*kVpx{tGCBiPb3hbU zu-dVPho>B>Lb(sleH&+x=I22rGgCx7Pn?|3fHTN!O8BOP??n>6#i&!)1*F#w+G>UB z1wmUW)wa1=k8wh`v!gGJ?H)KwIDckG6Y>^4P~tqH&_nl>Z(FBtMGzC66P>R?XYWp$ zq!8X2lt+WAF@Q^kYl*0OOe%C2o%^w8a-#Y6+6XGxJc7*nM!yZew*27Wr~c5%ZFH;c?EAB0OHh2s>gb4>nv}4Psc|)%?o9lQXc~Nt;^jlEOU<& z(&uL9edE}bijTsw@T7z$CG-=N(Es|^f7bv1f4BeY|NQ&^{qNfU>)-$R*Bd?X+SS%p zUY8DSsDo~NZX_j??fOZpv}HYZ0lf>^zfCPyuU(FikJm131Cc?e&qD>JZ5oCiZvmz8fc>i&8UH)XH+aj$Ds~~O-OWGX_Rlcb1f|v z_8AdIsFrMIVdr7?KIi-GX&lK@LO&(+KO&)j8nU>cFWv;Il7q@B5N$~)&7%#)(*00? z{3DRv<(eD-%s?~0g+95at#QTD(@uo!{cZM|3FeLR(kTv{;=rE}2R@D2>Y~McKy6h( zS5Bxw185*7wNXm*gP6V5Vis>kyO=FSo#k)LW=K(tGrcg69B-~)#wAU8+PtUD`$abI zv8{`O1Hxr{1D67=aRKQrW67oVam=Z9yJGO77?hn526b2b&^=hYo7Y?+6Q#9 z3C#)3AA#o6)0D}Uq*9^sCR9QZ$c=5v45Y0`yWpW*>-&J+7b=;se*)H-N{XYN_5k+# zfkx#Du%v!*>`ax?R4JXVQhFM&ZEeUSI;^8BXvlVeMFw)(LUm;=<5*Hdyy?B92HAQ3 zGP-=R%xpo^NF2GVkC10(tUT}l7X1~p#!Q?Ov=g*H0on(St*!bPqY|`A3QB?yV-4`p zIEPp4_1HZ9yP)L;JogN3Mi!rKq3*)2E{JE%({kU=_HCZ#Umq~%>71v3&OD{#3?yoW&i3fNMd z@k1Ap8Bw%wmech74=9Ge9c+TN%rf9v2K=frU`p+kFo4!&fF>8H#SOxmDOOTG3{JZ{ zO?UQHE#-oP_i38pQdI0TZLr@D7QF81#`sG|HTTuIul_mvYE?~Mwzfl!&44o)YN-K| zgNL@YCmqOS*-A$5B_`!NqOSm(M&%>V%relmaGWL#b~_AMLbB;xozB%Cajri7{KZN> z1~IH5+rg$TkgZiH64onG=D`Uo?+4W1PT2BZE&MBBNhrfUPON0ig~XZktb+|bQ0PQg zBomiXIH#d?8d_guXr*dP*|hr3LqV4=P;={E<0Wt%jhGJbzww6p-aGMIc>0^|7+Rya z{E`ovnC`46>Iolk+VIsII81a>z>@<05eoQ$bL!ICPznUhwymcNLe{lH^riH*FD>{$ z7{p`f-1V+*sW2Y}!i1<6BChz4qVr0iPoZc$#ST;K@FKCpz=|wOg3#)qSQ4_z0$dAg zx8BqaxK!f}?Pl|Sym5K=*IdueQ2)a0CfmlUo>uQoc>fmjZFH7onqd$#4B|(^ARZW< z!mXsbybe&mzbl z@Z>O0af>YHiR|wWPq`8;7!|qX@lSY8c)kLj&WucCV6NBpEoNmLNk_WC z^H!%*ewt*ip0-36(a+zUEiz{b|Azy7uO&sL6qLDm&c*XZizhD8lH6dl5}>0p#EKo3 zbs4$FVDkfcgBNtljf=`(=-g$6*!?4*VOu=OU6S;?r|koRzw4)M(573S=$z<$4LYke zUl|q5R{~w#Ahj#3>DqA7Bszx9+qE&98)mnNKUBg#B9BsnnFaksa6TYLxCW;el$;q2 zGo#@rG8!HMXB}%>lcD<7>13loSUN0KmezZY#g9E~9{?xqJ#0<+GpaW=Ow7&vJa9hH z8gotAdKQ`TzA5kf5qaMO;B@7sWeITIw$6qf!dr*Fj+)smw4XaU&E8~3$QRD?89cUW z5l~H4+3@d4LZJjzskW&8dQ}>5wK4RazN?7h$hQv3YZDZhbF1mlRdk{Fs}zT|K>&LZ>;g z?{l@^q7zuu=h&QM^C!mU(@yNcUO0`w2W>$_+@Q6_pq!+sOEWz>OmCUV@=f$jch*pI zDxXn*&Z(SSPK-{tzl46v=47&&bv?7L|E#R*uq6za4l8a|FO3Z{c!e~h&a}4Zhuoi5 z-sHB=DJ`1PqMwi! zJq=i1y=Zy?tgCNAn%)I$?gCazl+PX35jB(y&#QlVBL2@Jc$!?M z$>k?ZE>8m%dqe6`L8%d_jZ1S=g=M9}+#Sby46yNrH`2r|fVG`tji&mS35%J=bUEMr zV-xnv))PT04Qt8A}+d;tc%?pm@Zu+&Rf6?0) zDlWpBcotyG{rsY9z;bb%o#3+*{LktH?<0FGh#-Xwbd&;>SA=D>Zj89u*bV_U-{>Yw z{F_F^tzDQtCaeW=!E`(gu+Q{M2+lOXnFjbXX@Jk~uyrgN&7ejL(6&8^>%yD!bYP{- zlw(mU`9}22lQ_)rLznMlq|BIn8epG!631*qoNb6d(}wsoV7sqsLkD2v4oaL5(FELE zkJ_Y1I|^92y~CE>32Ru=zmQHvBt$V!o3KxiPF|9xrfF)LenQjqG+=GZsMi%itZtrh z-QtjFg}P9#V^QyTsB>a_@!p%Tx_5_VH2r)MTUer+=UGo;yRQ(oUjdujEqI<`=Nb0T zI>W9=+;Kof-a1XCLHf#@Zh|XHF3UJZ5^wQ=cks%4R~?SXj~B5Srl)zFMiM`O*Q*sa z!^|e-G%2S)igF^QQYb1o>W0@Q(AXSMrLNA6$`NPzrV_rR^8d|IN3x`UaKt7dwuSYc zrX;re!o=(Os_8lx*tx*|Q48!)jMBRRM;d6gfDA3LcvTc^TXEn)yx!_yyS#^GC%o5O zF4OG&rV}1T2uaSuYusO8uVqe(rnBUKmi+%&CI8Y_cToe3&EiU?5Sx&g*GS8;utle`o#>WJ=Glkxe>)AAAl1_V`#=HP^@BL|Qk^jw;>i&IISg@d3udigYipa1c!gHT zK{Ud-bE7z5t-Ih=?9PDQZ6(HV{KTsv8fD4T@cIPdv^BEL1$Hj5f7AlIu97XSfruq2 zj)Z2?pvG3PzfxJ&qYLbvfS11+>mYK$==uO z6}oPKV6Y6THHSdETKp$VK|=^EJ1YtN&GEYBG`2* ziKmkIN0h`5tgAGZSXCQ%^#qmHAh=g((k;A^#d3^avNyZ8uG&trL~NdduX$!9u+A)OT$ zv*O}K6&Jl=O0f=7+BQ6Mh1#894fa8`Hn*e0({AUtlsDWF4hDvhehKO}qRstgXXTAP zS*$2NTZv~Y@vB;i%g|L8m#x@>KszP0!USt;(N+@_KD2lezaLS4i%#E_;RhD-4|Hzc z02FaLaqoNzoLef~1m^_jYrwg9(9-(?!kej0twIgzAX%(zrZ(0?oGs}+7pm=Q0)x}( z%fl86E3y|n51nxzo!>ayOtRT}I$KX))OuPLZ!%&4;wqp{0>9r0YSQRjbjGfr zC^%d`l0-Lj7G&f&vG(*Sbc*J@sLYGXi!Lf-gJ!D&EvL#V2336m#$VAG~+|H+x@_Bgw97xtBLC0%A}4 z0%{+U%mfrrs8@LS`^See<9cL9ScW&S_?`nzd}Pz(qz+H>m(R`~sie-JG&T@v0|Lu@ zch-_s2ys00?j*Xfd^tPgjnn-dot{6*(Vyr{CuJ2X<-E~(+l=;kbP}4Zz_Jxs_8oy` zcZ^O7&D}b}<}M2t3qgRg528J9|$$N1Do^Fc_e`s z@n1!@l+K8x=dHC*O5j)e{Yt<8p7i@W(AhZpZl%NCra?tqpr%gmHgz`JM)*T(t?E}1 z3sf%R7d%*NMU3BXoyw9?ocuJt_KrxDkB)5>q(uiUI_On&P^*-)MKLoIq$@*gb%!LQ ztyQC19-@P8B2(ichlkE6l<#wM_5my6i|L?1Ex2Bs>&5w^7pEo@ZCgMO93W~AF&cqJ z?>@+EujL_h+E?lI6P@z*!SCoaRpToCd~&2PDHK3%jFy`gW((3%bq7J=Y`ARdje$E?^s7qoQIqjUrge$UaIk@Cdq ze5Mfo38`%qEV?eA>+<=c%ja&R_pvMV(r3zT6^L2|XeV~Aqw>C;K2i?|T$(+jdG)C< zDN|6Onbl~OWyi5U z<}JGoS~>KV2`9a$_03djw1{E{kbUlj`f&e#vi-2OExazgo{rZ$UZ@eyJ~~545s+pD zvSEiE8&%%Y_WIa8)ZeI~FUILnoC%haDDO%lBE~?XVrRw1Bj0|ZBK^MY&Q+gz!E?d$ zJK*{BIMtS#TN$tw+d-l;v^^78V>9w*tv{wOx(Ql2RLzT$@b!hNqJ>q3&Ksw<-=`l5 z-;nf0_%6ctMT9SoPD)&%;154bHOMpp)RtsTHZPA|N&VK9^tgis4QJ}^KhT^PB6SuC zK8x@rx;;+mgWZhX(90r^7J2j?y*tpHydE;14L|0WdlOb<|5|B z<1yYS-o&_nT6AUB6n;jgy8XiSTB^)^KjX6&UB4|l`q=SHQVOn@>3W%d$IJ8{Xj1i# z7O-tmK@btDF#?gL)-iT&j}6Vd;Gf$D=g^E}J)o3`UxoC_TC|*YBn`fKg!v?-k6>9- zb4|?`P0c-wT5ki0dk5LcAD8l`K~l(aIuvRTdH1K0F*Wdw}fRAZ(v3ZlnoG8~uJ|(NAR3*VfQK zRSHfe(?7_ZhtU+0*X#aR*L!olH(&MM+J?9RUD7a)qOGfk>8Bvq0)pwea@eVTD1~q(x7HZqruqoc( zC^*qccO;(VXLO2C;*|}WTdmt{2@qkD_zK==&2g1uuGlOmi}MPgIzpVI;_Q*369CHkSPG*kscpD~f1E z5xppiXtU7Xj3EVQkDwv6nh3Sxo;9UKsSiPuzbeS4@~8fK(?W999k`?grsQdT4srXb z`3agb{~#7L7c^f3O;p{7S%MBKAk->kNt>IkMNqahJ{OvFXjlx*8K>^R@U-LR z6IL>vj`4-eh0NC=bK88jHp~VGA`nJ}Dtm!_Gu>NBwFi1u<~}Qz@+Ct%_t^su$k@tz z*2!$iE}40r$oRntO%ZVxBf<>u&6|#{D%b zZ_xa5pJl%AL3^O7=zI?T9Gb4lOhqEj8k)~MHPu#i;HnOMS#==B7<;oFlBbTg?h3KT z4!-Yu?oqACW2yta0ZpZg9A?Fn;`OfS>V_7_ezE_#r)HQg7HF|RFJghbdlY1WR#ici z9V*rxwv4{*Rrlw9~o3wuH{ZcWWNgl6E(Hu?veScnNxSx$RwVz~{@ zPxg~wBwPU{E1=|60VPqi_!fZ32vUgV!&AXqvbb!R_%J%Zw4bOPJ~w5qu)oNGOvFQq zo(0Y)it`5I)3vs)_&rrh3ANV3qprVO)6wLVa=GLf0LLcRWRT>t*s3{HKQ z(9ZfJc8NUEe)62aJ*cd?x#s4J=4RGfeuToCN(bQ`p|+;LqmHaOO2|WsAf($FL4068 zG0epG3ySHiI8i-qseOtIQpNS)To29{JvjI3iaZE*N&;!b5TpUkJX)14*&pJ9kl#w^ z|G3ino0{*#;H2dD3(9e}p#_7T1{-*kgPI=o}A6#pv4J@zdbXOPCABZ~XzWGE>kejdj=DKgb>b@D<)`tv- zYPNw`-5_XJXoeIr%AWiEIYCq|#23D0+B|9}6JeyQ0YxcuR;%D?_su7yv=Y8su zsvAn{G(6ZrsU(O?fyA6Yy2T#dyWb!1{sz1+h9+Kw-ah!a(jxoSe}biiy327X!&A__ ztAgy~O6ytB*W6rl^F?zrXUUk99U2Y+DWZ_W1+a11wUoZmx#*moDM#ouB)W1zSVS@z z(@s00Al_z!J~OqNKmIe;gL6GNU-IBg+oj|HEW<%^&Q2-~Ft$1(RYyEzLs5P6e|<4K z%R%~OV4+{@I}0bxD3BBN2T#O!c|=)_*sBryRgKu4~S5r#9P=b?97&&Q~2exr|I4 z0kzHQ>n&$MtrjSoTh}cLkB0(-ZqLrV(2=s1vEa3*2n&X0DH`X!JD*b47QAO4o@V64 zqEAq^qOxkPSIzaSYOWPG_UZ~uQ}$k4o!#>S>OFTQX(b;8=hp`n%}Y55^a>T!Ulv=A z8G+z_9w~&kBM?46JEbtKXXko$zUbLWJMUEM05z>MJ-R`T&0#A8Y2#6XAERvjt&iwW zqf_Xx6U9@?dlF_QGut$#oCeNv+m-V9+8OAy?kVe@@}hgn$l!`rU>_YpIyGoE1HQVc z7ugx>x!~ly@WHjyV>±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