From 9a73c2ab60497b18494dde01b70012da778341e5 Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Tue, 9 Apr 2024 13:12:17 -0400 Subject: [PATCH 01/28] add semaphore files --- collector/go.sum | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/collector/go.sum b/collector/go.sum index 982108ba..5521155f 100644 --- a/collector/go.sum +++ b/collector/go.sum @@ -65,8 +65,14 @@ github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDN github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +<<<<<<< HEAD +======= +github.com/wk8/go-ordered-map v1.0.0 h1:BV7z+2PaK8LTSd/mWgY12HyMAo5CEgkHqbkVq2thqr8= +github.com/wk8/go-ordered-map v1.0.0/go.mod h1:9ZIbRunKbuvfPKyBP1SIKLcXNlv74YCOZ3t3VTS6gRk= +>>>>>>> 9668783 (add semaphore files) github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -143,5 +149,6 @@ google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHh gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From e30c2208b42829579eb772155f1b6900654f9740 Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Sun, 14 Apr 2024 19:41:08 -0400 Subject: [PATCH 02/28] add uncompSz to proto defintion and apply semaphore --- api/experimental/arrow/v1/arrow_service.pb.go | 220 +++++++++--------- .../arrow/v1/arrow_service_grpc.pb.go | 2 +- .../internal/arrow/stream.go | 1 + .../receiver/otelarrowreceiver/config.go | 5 + .../otelarrowreceiver/internal/arrow/arrow.go | 14 ++ .../internal/arrow/arrow_test.go | 2 + .../receiver/otelarrowreceiver/otelarrow.go | 4 +- .../experimental/arrow/v1/arrow_service.proto | 3 + 8 files changed, 145 insertions(+), 106 deletions(-) diff --git a/api/experimental/arrow/v1/arrow_service.pb.go b/api/experimental/arrow/v1/arrow_service.pb.go index 8dd1045b..95886685 100644 --- a/api/experimental/arrow/v1/arrow_service.pb.go +++ b/api/experimental/arrow/v1/arrow_service.pb.go @@ -22,8 +22,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v3.19.4 +// protoc-gen-go v1.33.0 +// protoc v4.25.3 // source: opentelemetry/proto/experimental/arrow/v1/arrow_service.proto package v1 @@ -249,6 +249,8 @@ type BatchArrowRecords struct { ArrowPayloads []*ArrowPayload `protobuf:"bytes,2,rep,name=arrow_payloads,json=arrowPayloads,proto3" json:"arrow_payloads,omitempty"` // [optional] Headers associated with this batch, encoded using hpack. Headers []byte `protobuf:"bytes,3,opt,name=headers,proto3" json:"headers,omitempty"` + // [mandatory] The uncompressed size of the batch. + UncompressedSize uint64 `protobuf:"varint,4,opt,name=uncompressed_size,json=uncompressedSize,proto3" json:"uncompressed_size,omitempty"` } func (x *BatchArrowRecords) Reset() { @@ -304,6 +306,13 @@ func (x *BatchArrowRecords) GetHeaders() []byte { return nil } +func (x *BatchArrowRecords) GetUncompressedSize() uint64 { + if x != nil { + return x.UncompressedSize + } + return 0 +} + // Represents a batch of OTel Arrow entities. type ArrowPayload struct { state protoimpl.MessageState @@ -452,7 +461,7 @@ var file_opentelemetry_proto_experimental_arrow_v1_arrow_service_proto_rawDesc = 0x77, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x29, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, - 0x6c, 0x2e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x22, 0xa8, 0x01, 0x0a, 0x11, 0x42, + 0x6c, 0x2e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x22, 0xd5, 0x01, 0x0a, 0x11, 0x42, 0x61, 0x74, 0x63, 0x68, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x62, 0x61, 0x74, 0x63, 0x68, 0x49, 0x64, 0x12, 0x5e, 0x0a, 0x0e, 0x61, @@ -463,112 +472,115 @@ var file_opentelemetry_proto_experimental_arrow_v1_arrow_service_proto_rawDesc = 0x41, 0x72, 0x72, 0x6f, 0x77, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x0d, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x68, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x73, 0x22, 0x94, 0x01, 0x0a, 0x0c, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x50, - 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x63, 0x68, 0x65, 0x6d, - 0x61, 0x49, 0x64, 0x12, 0x4f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x3b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, - 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, - 0x6e, 0x74, 0x61, 0x6c, 0x2e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x72, - 0x72, 0x6f, 0x77, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x22, 0xa7, 0x01, 0x0a, - 0x0b, 0x42, 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x19, 0x0a, 0x08, - 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, - 0x62, 0x61, 0x74, 0x63, 0x68, 0x49, 0x64, 0x12, 0x56, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x35, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2e, - 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, - 0x6f, 0x64, 0x65, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x12, - 0x25, 0x0a, 0x0e, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2a, 0xf9, 0x04, 0x0a, 0x10, 0x41, 0x72, 0x72, 0x6f, 0x77, - 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, - 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x53, 0x4f, - 0x55, 0x52, 0x43, 0x45, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, - 0x53, 0x43, 0x4f, 0x50, 0x45, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x02, 0x12, 0x16, 0x0a, - 0x12, 0x55, 0x4e, 0x49, 0x56, 0x41, 0x52, 0x49, 0x41, 0x54, 0x45, 0x5f, 0x4d, 0x45, 0x54, 0x52, - 0x49, 0x43, 0x53, 0x10, 0x0a, 0x12, 0x16, 0x0a, 0x12, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x5f, - 0x44, 0x41, 0x54, 0x41, 0x5f, 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x53, 0x10, 0x0b, 0x12, 0x17, 0x0a, - 0x13, 0x53, 0x55, 0x4d, 0x4d, 0x41, 0x52, 0x59, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x50, 0x4f, - 0x49, 0x4e, 0x54, 0x53, 0x10, 0x0c, 0x12, 0x19, 0x0a, 0x15, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, - 0x52, 0x41, 0x4d, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x53, 0x10, - 0x0d, 0x12, 0x1d, 0x0a, 0x19, 0x45, 0x58, 0x50, 0x5f, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, - 0x41, 0x4d, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x53, 0x10, 0x0e, - 0x12, 0x13, 0x0a, 0x0f, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x5f, 0x44, 0x50, 0x5f, 0x41, 0x54, - 0x54, 0x52, 0x53, 0x10, 0x0f, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x55, 0x4d, 0x4d, 0x41, 0x52, 0x59, - 0x5f, 0x44, 0x50, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x10, 0x12, 0x16, 0x0a, 0x12, 0x48, - 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x5f, 0x44, 0x50, 0x5f, 0x41, 0x54, 0x54, 0x52, - 0x53, 0x10, 0x11, 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x58, 0x50, 0x5f, 0x48, 0x49, 0x53, 0x54, 0x4f, - 0x47, 0x52, 0x41, 0x4d, 0x5f, 0x44, 0x50, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x12, 0x12, - 0x17, 0x0a, 0x13, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x5f, 0x44, 0x50, 0x5f, 0x45, 0x58, 0x45, - 0x4d, 0x50, 0x4c, 0x41, 0x52, 0x53, 0x10, 0x13, 0x12, 0x1a, 0x0a, 0x16, 0x48, 0x49, 0x53, 0x54, - 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x5f, 0x44, 0x50, 0x5f, 0x45, 0x58, 0x45, 0x4d, 0x50, 0x4c, 0x41, - 0x52, 0x53, 0x10, 0x14, 0x12, 0x1e, 0x0a, 0x1a, 0x45, 0x58, 0x50, 0x5f, 0x48, 0x49, 0x53, 0x54, - 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x5f, 0x44, 0x50, 0x5f, 0x45, 0x58, 0x45, 0x4d, 0x50, 0x4c, 0x41, - 0x52, 0x53, 0x10, 0x15, 0x12, 0x1c, 0x0a, 0x18, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x5f, 0x44, - 0x50, 0x5f, 0x45, 0x58, 0x45, 0x4d, 0x50, 0x4c, 0x41, 0x52, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, - 0x10, 0x16, 0x12, 0x1f, 0x0a, 0x1b, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x5f, - 0x44, 0x50, 0x5f, 0x45, 0x58, 0x45, 0x4d, 0x50, 0x4c, 0x41, 0x52, 0x5f, 0x41, 0x54, 0x54, 0x52, - 0x53, 0x10, 0x17, 0x12, 0x23, 0x0a, 0x1f, 0x45, 0x58, 0x50, 0x5f, 0x48, 0x49, 0x53, 0x54, 0x4f, - 0x47, 0x52, 0x41, 0x4d, 0x5f, 0x44, 0x50, 0x5f, 0x45, 0x58, 0x45, 0x4d, 0x50, 0x4c, 0x41, 0x52, - 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x18, 0x12, 0x18, 0x0a, 0x14, 0x4d, 0x55, 0x4c, 0x54, + 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x75, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x64, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x10, 0x75, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x69, + 0x7a, 0x65, 0x22, 0x94, 0x01, 0x0a, 0x0c, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x50, 0x61, 0x79, 0x6c, + 0x6f, 0x61, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x49, 0x64, + 0x12, 0x4f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3b, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, + 0x6c, 0x2e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x72, 0x72, 0x6f, 0x77, + 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x22, 0xa7, 0x01, 0x0a, 0x0b, 0x42, 0x61, + 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x61, 0x74, + 0x63, 0x68, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x62, 0x61, 0x74, + 0x63, 0x68, 0x49, 0x64, 0x12, 0x56, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x63, + 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x35, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2e, 0x61, 0x72, 0x72, + 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, + 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x25, 0x0a, 0x0e, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x2a, 0xf9, 0x04, 0x0a, 0x10, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x50, 0x61, 0x79, + 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, + 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, + 0x45, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x43, 0x4f, + 0x50, 0x45, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x02, 0x12, 0x16, 0x0a, 0x12, 0x55, 0x4e, 0x49, 0x56, 0x41, 0x52, 0x49, 0x41, 0x54, 0x45, 0x5f, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, - 0x10, 0x19, 0x12, 0x08, 0x0a, 0x04, 0x4c, 0x4f, 0x47, 0x53, 0x10, 0x1e, 0x12, 0x0d, 0x0a, 0x09, - 0x4c, 0x4f, 0x47, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x1f, 0x12, 0x09, 0x0a, 0x05, 0x53, - 0x50, 0x41, 0x4e, 0x53, 0x10, 0x28, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x50, 0x41, 0x4e, 0x5f, 0x41, - 0x54, 0x54, 0x52, 0x53, 0x10, 0x29, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x50, 0x41, 0x4e, 0x5f, 0x45, - 0x56, 0x45, 0x4e, 0x54, 0x53, 0x10, 0x2a, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x50, 0x41, 0x4e, 0x5f, - 0x4c, 0x49, 0x4e, 0x4b, 0x53, 0x10, 0x2b, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x50, 0x41, 0x4e, 0x5f, - 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x2c, 0x12, 0x13, 0x0a, - 0x0f, 0x53, 0x50, 0x41, 0x4e, 0x5f, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, - 0x10, 0x2d, 0x2a, 0x61, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, - 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x4b, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x41, 0x4e, 0x43, - 0x45, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x41, 0x56, 0x41, 0x49, - 0x4c, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x0e, 0x12, 0x14, 0x0a, 0x10, 0x49, 0x4e, 0x56, 0x41, 0x4c, - 0x49, 0x44, 0x5f, 0x41, 0x52, 0x47, 0x55, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x03, 0x12, 0x16, 0x0a, - 0x12, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x45, 0x58, 0x48, 0x41, 0x55, 0x53, - 0x54, 0x45, 0x44, 0x10, 0x08, 0x32, 0xa0, 0x01, 0x0a, 0x12, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x54, - 0x72, 0x61, 0x63, 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x89, 0x01, 0x0a, - 0x0b, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x54, 0x72, 0x61, 0x63, 0x65, 0x73, 0x12, 0x3c, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2e, - 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x41, 0x72, - 0x72, 0x6f, 0x77, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x1a, 0x36, 0x2e, 0x6f, 0x70, 0x65, - 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2e, 0x61, 0x72, - 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x32, 0x9c, 0x01, 0x0a, 0x10, 0x41, 0x72, 0x72, - 0x6f, 0x77, 0x4c, 0x6f, 0x67, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x87, 0x01, - 0x0a, 0x09, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x3c, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2e, 0x61, - 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x41, 0x72, 0x72, - 0x6f, 0x77, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x1a, 0x36, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x10, 0x0a, 0x12, 0x16, 0x0a, 0x12, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x5f, 0x44, 0x41, 0x54, + 0x41, 0x5f, 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x53, 0x10, 0x0b, 0x12, 0x17, 0x0a, 0x13, 0x53, 0x55, + 0x4d, 0x4d, 0x41, 0x52, 0x59, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x50, 0x4f, 0x49, 0x4e, 0x54, + 0x53, 0x10, 0x0c, 0x12, 0x19, 0x0a, 0x15, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, 0x4d, + 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x53, 0x10, 0x0d, 0x12, 0x1d, + 0x0a, 0x19, 0x45, 0x58, 0x50, 0x5f, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x5f, + 0x44, 0x41, 0x54, 0x41, 0x5f, 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x53, 0x10, 0x0e, 0x12, 0x13, 0x0a, + 0x0f, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x5f, 0x44, 0x50, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, + 0x10, 0x0f, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x55, 0x4d, 0x4d, 0x41, 0x52, 0x59, 0x5f, 0x44, 0x50, + 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x10, 0x12, 0x16, 0x0a, 0x12, 0x48, 0x49, 0x53, 0x54, + 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x5f, 0x44, 0x50, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x11, + 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x58, 0x50, 0x5f, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, + 0x4d, 0x5f, 0x44, 0x50, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x12, 0x12, 0x17, 0x0a, 0x13, + 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x5f, 0x44, 0x50, 0x5f, 0x45, 0x58, 0x45, 0x4d, 0x50, 0x4c, + 0x41, 0x52, 0x53, 0x10, 0x13, 0x12, 0x1a, 0x0a, 0x16, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, + 0x41, 0x4d, 0x5f, 0x44, 0x50, 0x5f, 0x45, 0x58, 0x45, 0x4d, 0x50, 0x4c, 0x41, 0x52, 0x53, 0x10, + 0x14, 0x12, 0x1e, 0x0a, 0x1a, 0x45, 0x58, 0x50, 0x5f, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, + 0x41, 0x4d, 0x5f, 0x44, 0x50, 0x5f, 0x45, 0x58, 0x45, 0x4d, 0x50, 0x4c, 0x41, 0x52, 0x53, 0x10, + 0x15, 0x12, 0x1c, 0x0a, 0x18, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x5f, 0x44, 0x50, 0x5f, 0x45, + 0x58, 0x45, 0x4d, 0x50, 0x4c, 0x41, 0x52, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x16, 0x12, + 0x1f, 0x0a, 0x1b, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x5f, 0x44, 0x50, 0x5f, + 0x45, 0x58, 0x45, 0x4d, 0x50, 0x4c, 0x41, 0x52, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x17, + 0x12, 0x23, 0x0a, 0x1f, 0x45, 0x58, 0x50, 0x5f, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, + 0x4d, 0x5f, 0x44, 0x50, 0x5f, 0x45, 0x58, 0x45, 0x4d, 0x50, 0x4c, 0x41, 0x52, 0x5f, 0x41, 0x54, + 0x54, 0x52, 0x53, 0x10, 0x18, 0x12, 0x18, 0x0a, 0x14, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x56, 0x41, + 0x52, 0x49, 0x41, 0x54, 0x45, 0x5f, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x10, 0x19, 0x12, + 0x08, 0x0a, 0x04, 0x4c, 0x4f, 0x47, 0x53, 0x10, 0x1e, 0x12, 0x0d, 0x0a, 0x09, 0x4c, 0x4f, 0x47, + 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x1f, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x50, 0x41, 0x4e, + 0x53, 0x10, 0x28, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x50, 0x41, 0x4e, 0x5f, 0x41, 0x54, 0x54, 0x52, + 0x53, 0x10, 0x29, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x50, 0x41, 0x4e, 0x5f, 0x45, 0x56, 0x45, 0x4e, + 0x54, 0x53, 0x10, 0x2a, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x50, 0x41, 0x4e, 0x5f, 0x4c, 0x49, 0x4e, + 0x4b, 0x53, 0x10, 0x2b, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x50, 0x41, 0x4e, 0x5f, 0x45, 0x56, 0x45, + 0x4e, 0x54, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x2c, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x50, + 0x41, 0x4e, 0x5f, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x2d, 0x2a, + 0x61, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x06, 0x0a, + 0x02, 0x4f, 0x4b, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x45, + 0x44, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x41, 0x56, 0x41, 0x49, 0x4c, 0x41, 0x42, + 0x4c, 0x45, 0x10, 0x0e, 0x12, 0x14, 0x0a, 0x10, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, + 0x41, 0x52, 0x47, 0x55, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x03, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x45, + 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x45, 0x58, 0x48, 0x41, 0x55, 0x53, 0x54, 0x45, 0x44, + 0x10, 0x08, 0x32, 0xa0, 0x01, 0x0a, 0x12, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x54, 0x72, 0x61, 0x63, + 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x89, 0x01, 0x0a, 0x0b, 0x41, 0x72, + 0x72, 0x6f, 0x77, 0x54, 0x72, 0x61, 0x63, 0x65, 0x73, 0x12, 0x3c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2e, 0x61, 0x72, 0x72, - 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x32, 0xa2, 0x01, 0x0a, 0x13, 0x41, 0x72, 0x72, 0x6f, - 0x77, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, - 0x8a, 0x01, 0x0a, 0x0c, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, - 0x12, 0x3c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, - 0x74, 0x61, 0x6c, 0x2e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, - 0x63, 0x68, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x1a, 0x36, + 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x41, 0x72, 0x72, 0x6f, 0x77, + 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x1a, 0x36, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, + 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, + 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2e, 0x61, 0x72, 0x72, 0x6f, 0x77, + 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, + 0x00, 0x28, 0x01, 0x30, 0x01, 0x32, 0x9c, 0x01, 0x0a, 0x10, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x4c, + 0x6f, 0x67, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x87, 0x01, 0x0a, 0x09, 0x41, + 0x72, 0x72, 0x6f, 0x77, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x3c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, + 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, + 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2e, 0x61, 0x72, 0x72, 0x6f, + 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x52, + 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x1a, 0x36, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, + 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x70, + 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2e, + 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, + 0x28, 0x01, 0x30, 0x01, 0x32, 0xa2, 0x01, 0x0a, 0x13, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x4d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x8a, 0x01, 0x0a, + 0x0c, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x3c, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, + 0x2e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x41, + 0x72, 0x72, 0x6f, 0x77, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x1a, 0x36, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2e, 0x61, + 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x83, 0x01, 0x0a, 0x2c, 0x69, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, - 0x6c, 0x2e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x83, 0x01, 0x0a, - 0x2c, 0x69, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, - 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, - 0x6e, 0x74, 0x61, 0x6c, 0x2e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x42, 0x11, 0x41, - 0x72, 0x72, 0x6f, 0x77, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x50, 0x01, 0x5a, 0x3e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, - 0x70, 0x65, 0x6e, 0x2d, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2f, 0x6f, 0x74, - 0x65, 0x6c, 0x2d, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x65, 0x78, 0x70, - 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2f, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2f, - 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6c, 0x2e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x42, 0x11, 0x41, 0x72, 0x72, 0x6f, + 0x77, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, + 0x3e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, + 0x2d, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2f, 0x6f, 0x74, 0x65, 0x6c, 0x2d, + 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, + 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2f, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2f, 0x76, 0x31, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/api/experimental/arrow/v1/arrow_service_grpc.pb.go b/api/experimental/arrow/v1/arrow_service_grpc.pb.go index 1d0a1b3b..fbc32a19 100644 --- a/api/experimental/arrow/v1/arrow_service_grpc.pb.go +++ b/api/experimental/arrow/v1/arrow_service_grpc.pb.go @@ -23,7 +23,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v3.19.4 +// - protoc v4.25.3 // source: opentelemetry/proto/experimental/arrow/v1/arrow_service.proto package v1 diff --git a/collector/exporter/otelarrowexporter/internal/arrow/stream.go b/collector/exporter/otelarrowexporter/internal/arrow/stream.go index 3a55105b..24b0532e 100644 --- a/collector/exporter/otelarrowexporter/internal/arrow/stream.go +++ b/collector/exporter/otelarrowexporter/internal/arrow/stream.go @@ -318,6 +318,7 @@ func (s *Stream) encodeAndSend(wri writeItem, hdrsBuf *bytes.Buffer, hdrsEnc *hp wri.errCh <- consumererror.NewPermanent(err) return err } + batch.UncompressedSize = uint64(wri.uncompSize) // Optionally include outgoing metadata, if present. if len(wri.md) != 0 { diff --git a/collector/receiver/otelarrowreceiver/config.go b/collector/receiver/otelarrowreceiver/config.go index 78f9b53e..0c72bd77 100644 --- a/collector/receiver/otelarrowreceiver/config.go +++ b/collector/receiver/otelarrowreceiver/config.go @@ -24,6 +24,11 @@ type ArrowConfig struct { // passing through, they will see ResourceExhausted errors. MemoryLimitMiB uint64 `mapstructure:"memory_limit_mib"` + // WaiterLimit is the limit on the number of waiters waiting to be processed and consumed. + // This is a dimension of memory limiting to ensure waiters are not consuming an + // unexpectedly large amount of memory in the arrow receiver. + WaiterLimit int64 `mapstructure:"waiter_limit"` + // Zstd settings apply to OTel-Arrow use of gRPC specifically. Zstd zstd.DecoderConfig `mapstructure:"zstd"` } diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go index a058ec82..3b95d425 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go @@ -37,6 +37,8 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" + + "github.com/open-telemetry/otel-arrow/collector/admission" ) const ( @@ -75,6 +77,7 @@ type Receiver struct { recvInFlightBytes metric.Int64UpDownCounter recvInFlightItems metric.Int64UpDownCounter recvInFlightRequests metric.Int64UpDownCounter + boundedQueue *admission.BoundedQueue } // New creates a new Receiver reference. @@ -85,6 +88,7 @@ func New( gsettings configgrpc.ServerConfig, authServer auth.Server, newConsumer func() arrowRecord.ConsumerAPI, + bq *admission.BoundedQueue, netReporter netstats.Interface, ) (*Receiver, error) { tracer := set.TelemetrySettings.TracerProvider.Tracer("otel-arrow-receiver") @@ -98,6 +102,7 @@ func New( newConsumer: newConsumer, gsettings: gsettings, netReporter: netReporter, + boundedQueue: bq, } meter := recv.telemetry.MeterProvider.Meter(scopeName) @@ -354,6 +359,13 @@ func (r *Receiver) anyStream(serverStream anyStreamServer, method string) (retEr // Receive a batch corresponding with one ptrace.Traces, pmetric.Metrics, // or plog.Logs item. req, err := serverStream.Recv() + + uncompSz := int64(req.GetUncompressedSize()) + // bounded queue to memory limit based on incoming uncompressed request size and waiters. + // Acquire will fail immediately if there are too many waiters, + // or will otherwise block until timeout or enough memory becomes available. + r.boundedQueue.Acquire(streamCtx, uncompSz) + if err != nil { // This includes the case where a client called CloseSend(), in // which case we see an EOF error here. @@ -388,6 +400,8 @@ func (r *Receiver) anyStream(serverStream anyStreamServer, method string) (retEr if err := r.processAndConsume(thisCtx, method, ac, req, serverStream, authErr); err != nil { return err } + + r.boundedQueue.Release(uncompSz) } } diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go index 76b1792c..a2e66016 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go @@ -43,6 +43,7 @@ import ( "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" + "github.com/open-telemetry/otel-arrow/collector/admission" "github.com/open-telemetry/otel-arrow/collector/receiver/otelarrowreceiver/internal/arrow/mock" ) @@ -344,6 +345,7 @@ func (ctc *commonTestCase) start(newConsumer func() arrowRecord.ConsumerAPI, opt gsettings, authServer, newConsumer, + admission.NewBoundedQueue(int64(10490000), int64(10)), netstats.Noop{}, ) require.NoError(ctc.T, err) diff --git a/collector/receiver/otelarrowreceiver/otelarrow.go b/collector/receiver/otelarrowreceiver/otelarrow.go index 273f74de..94162fb6 100644 --- a/collector/receiver/otelarrowreceiver/otelarrow.go +++ b/collector/receiver/otelarrowreceiver/otelarrow.go @@ -24,6 +24,7 @@ import ( "go.uber.org/zap" "google.golang.org/grpc" + "github.com/open-telemetry/otel-arrow/collector/admission" "github.com/open-telemetry/otel-arrow/collector/receiver/otelarrowreceiver/internal/arrow" "github.com/open-telemetry/otel-arrow/collector/receiver/otelarrowreceiver/internal/logs" "github.com/open-telemetry/otel-arrow/collector/receiver/otelarrowreceiver/internal/metrics" @@ -113,6 +114,7 @@ func (r *otelArrowReceiver) startProtocolServers(host component.Host) error { return err } } + bq := admission.NewBoundedQueue(int64(r.cfg.Arrow.MemoryLimitMiB<<20), r.cfg.Arrow.WaiterLimit) r.arrowReceiver, err = arrow.New(arrow.Consumers(r), r.settings, r.obsrepGRPC, r.cfg.GRPC, authServer, func() arrowRecord.ConsumerAPI { var opts []arrowRecord.Option @@ -124,7 +126,7 @@ func (r *otelArrowReceiver) startProtocolServers(host component.Host) error { opts = append(opts, arrowRecord.WithMeterProvider(r.settings.TelemetrySettings.MeterProvider, r.settings.TelemetrySettings.MetricsLevel)) } return arrowRecord.NewConsumer(opts...) - }, r.netReporter) + }, bq, r.netReporter) if err != nil { return err diff --git a/proto/opentelemetry/proto/experimental/arrow/v1/arrow_service.proto b/proto/opentelemetry/proto/experimental/arrow/v1/arrow_service.proto index 145a3e63..ba558c09 100644 --- a/proto/opentelemetry/proto/experimental/arrow/v1/arrow_service.proto +++ b/proto/opentelemetry/proto/experimental/arrow/v1/arrow_service.proto @@ -72,6 +72,9 @@ message BatchArrowRecords { // [optional] Headers associated with this batch, encoded using hpack. bytes headers = 3; + + // [mandatory] The uncompressed size of the batch. + uint64 uncompressed_size = 4; } // Enumeration of all the OTel Arrow payload types currently supported by the From 3ec41e4148e9e6b2e51e25d8decf5f338eb429ac Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Tue, 16 Apr 2024 06:29:08 -0400 Subject: [PATCH 03/28] add AdmissionLimitMiB separate from MemoryLimitMiB, always record uncompSz in exporter --- collector/examples/bridge/edge-collector.yaml | 90 +++++++++++-------- collector/examples/bridge/saas-collector.yaml | 59 +++--------- .../internal/arrow/stream.go | 2 + .../receiver/otelarrowreceiver/config.go | 2 + .../otelarrowreceiver/internal/arrow/arrow.go | 15 ++-- .../receiver/otelarrowreceiver/otelarrow.go | 2 +- 6 files changed, 83 insertions(+), 87 deletions(-) diff --git a/collector/examples/bridge/edge-collector.yaml b/collector/examples/bridge/edge-collector.yaml index db9922d3..d2f7e6d0 100644 --- a/collector/examples/bridge/edge-collector.yaml +++ b/collector/examples/bridge/edge-collector.yaml @@ -1,52 +1,72 @@ receivers: - # otelarrow/standard is an OTelArrow receiver. - # it uses port 4317, the standard port for OTLP/gRPC. - # There are no required configuration fields. - otelarrow/standard: + # otelarrow/stdin is for regular traffic on the default gRPC port + otelarrow/stdin: + protocols: + grpc: + endpoint: 127.0.0.1:4317 + # otelarrow/loopback receives OTel-Arrow traffic on port 8100 + otelarrow/loopback: + protocols: + grpc: + endpoint: 127.0.0.1:8100 + max_recv_msg_size_mib: 3000 processors: - # The batch processor will benefit pipelines with small export sizes. concurrentbatch: + # the experiment processor routes 1 in 3 requests to the Arrow + # loopback exporter + experiment: + table: + - weight: 1 + exporters: [otelarrow/arrowout, logging/debug] + - weight: 2 + exporters: [otelarrow/stdout, logging/info] exporters: - # otelarrow/arrow is an OTel-Arrow exporter. - otelarrow/arrow: - # For the sample configuration, the other side of the bridge - # runs on port 8100. - endpoint: 127.0.0.1:8100 - - # For demonstration purposes, use an insecure port. This would - # also be normal for a collector behind a loadbalancer that - # terminates TLS. + # otelarrow/stdout sends OTel Arrow to an external destination + otelarrow/stdout: + endpoint: localhost:4317 + arrow: + disabled: false + disable_downgrade: true tls: insecure: true + # headers: + # lightstep-access-token: "${LIGHTSTEP_ACCESS_TOKEN}" - # Static headers will be attached to every export. - headers: - - X-Scope-OrgID: example_tenant - - # wait_for_ready lets the producer block until the connection - # is ready. + # otelarrow/arrowout sends standard OTal Arrow to an external destination + otelarrow/arrowout: + endpoint: 127.0.0.1:8100 + # wait_for_ready ensures the exporter doesn't fallback to standard + # OTLP because the exporter has not started. wait_for_ready: true + tls: + insecure: true + arrow: + num_streams: 1 + disable_downgrade: true - debug: + debug/info: + verbosity: normal + debug/debug: + verbosity: detailed service: pipelines: - traces: - receivers: [otelarrow/standard] - processors: [concurrentbatch] - exporters: [otelarrow/arrow, debug] - metrics: - receivers: [otelarrow/standard] - processors: [concurrentbatch] - exporters: [otelarrow/arrow, debug] + # the normal traces pipeline either routes directly to the + # standard output or via the loopback. it prints an info. + # traces/normal: + # receivers: [otelarrow/stdin] + # processors: [concurrentbatch, experiment] + # exporters: [debug/info, otelarrow/stdout, otelarrow/arrowout] + + # experiment processes data send via Arrow through the loopback. + # it prints a debug log. + traces/experiment: + receivers: [otelarrow/loopback] + processors: [] + exporters: [debug/info, otelarrow/stdout] telemetry: - resource: - "service.name": "example-bridge" metrics: - address: 127.0.0.1:8888 - level: detailed - logs: - level: info + address: localhost:8888 \ No newline at end of file diff --git a/collector/examples/bridge/saas-collector.yaml b/collector/examples/bridge/saas-collector.yaml index f1c91760..cd626798 100644 --- a/collector/examples/bridge/saas-collector.yaml +++ b/collector/examples/bridge/saas-collector.yaml @@ -1,60 +1,27 @@ receivers: - # otelarrow is an OTel Arrow receiver that will operate as the SaaS-side - # of the bridge. otelarrow: protocols: grpc: - # Port 5000 is the endpoint used in edge-collector. - endpoint: 127.0.0.1:8100 + endpoint: localhost:4317 + max_recv_msg_size_mib: 3000 + arrow: + admission_limit_mib: 30 + waiter_limit: 2 - # Include metadata so that the exporter can copy it - # to the next hop. - include_metadata: true - - keepalive: - server_parameters: - max_connection_age: 10s - max_connection_age_grace: 10s +processors: + concurrentbatch: exporters: - debug: - - otlphttp: - # You can use an HTTP listener on port 5001 to see the headers - # and raw data. - endpoint: http://127.0.0.1:8101 - compression: none - - # Associate the headers_setter extension with this exporter - # so that it passes through headers set on the edge collector. - auth: - authenticator: headers_setter - -extensions: - # Configure the headers_setter extension to propagate the - # X-Scope-OrgID property in the outgoing context. - headers_setter: + debug: + verbosity: basic + otelarrow/ls: + endpoint: ingest.lightstep.com:443 headers: - - key: X-Scope-OrgID - from_context: X-Scope-OrgID + "lightstep-access-token": ${LS_TOKEN} service: - extensions: [headers_setter] pipelines: traces: receivers: [otelarrow] - - # Note there is no need to re-apply the batch processor on the - # SaaS-side of a bridge. - processors: [] - exporters: [debug, otlphttp] - - metrics: - receivers: [otelarrow] processors: [] - exporters: [debug, otlphttp] - - telemetry: - metrics: - address: 127.0.0.1:8889 - level: normal + exporters: [debug, otelarrow/ls] \ No newline at end of file diff --git a/collector/exporter/otelarrowexporter/internal/arrow/stream.go b/collector/exporter/otelarrowexporter/internal/arrow/stream.go index 24b0532e..dba62410 100644 --- a/collector/exporter/otelarrowexporter/internal/arrow/stream.go +++ b/collector/exporter/otelarrowexporter/internal/arrow/stream.go @@ -318,6 +318,8 @@ func (s *Stream) encodeAndSend(wri writeItem, hdrsBuf *bytes.Buffer, hdrsEnc *hp wri.errCh <- consumererror.NewPermanent(err) return err } + fmt.Println("EXPORTER SIDE UNCOMP SIZE") + fmt.Println(wri.uncompSize) batch.UncompressedSize = uint64(wri.uncompSize) // Optionally include outgoing metadata, if present. diff --git a/collector/receiver/otelarrowreceiver/config.go b/collector/receiver/otelarrowreceiver/config.go index 0c72bd77..6e064cc2 100644 --- a/collector/receiver/otelarrowreceiver/config.go +++ b/collector/receiver/otelarrowreceiver/config.go @@ -24,6 +24,8 @@ type ArrowConfig struct { // passing through, they will see ResourceExhausted errors. MemoryLimitMiB uint64 `mapstructure:"memory_limit_mib"` + AdmissionLimitMiB uint64 `mapstructure:"admission_limit_mib"` + // WaiterLimit is the limit on the number of waiters waiting to be processed and consumed. // This is a dimension of memory limiting to ensure waiters are not consuming an // unexpectedly large amount of memory in the arrow receiver. diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go index 3b95d425..59a8e427 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go @@ -360,11 +360,6 @@ func (r *Receiver) anyStream(serverStream anyStreamServer, method string) (retEr // or plog.Logs item. req, err := serverStream.Recv() - uncompSz := int64(req.GetUncompressedSize()) - // bounded queue to memory limit based on incoming uncompressed request size and waiters. - // Acquire will fail immediately if there are too many waiters, - // or will otherwise block until timeout or enough memory becomes available. - r.boundedQueue.Acquire(streamCtx, uncompSz) if err != nil { // This includes the case where a client called CloseSend(), in @@ -379,6 +374,16 @@ func (r *Receiver) anyStream(serverStream anyStreamServer, method string) (retEr return err } + uncompSz := int64(req.GetUncompressedSize()) + // bounded queue to memory limit based on incoming uncompressed request size and waiters. + // Acquire will fail immediately if there are too many waiters, + // or will otherwise block until timeout or enough memory becomes available. + err = r.boundedQueue.Acquire(streamCtx, uncompSz) + if err != nil { + r.logStreamError(err) + return err + } + // Check for optional headers and set the incoming context. thisCtx, authHdrs, err := hrcv.combineHeaders(streamCtx, req.GetHeaders()) if err != nil { diff --git a/collector/receiver/otelarrowreceiver/otelarrow.go b/collector/receiver/otelarrowreceiver/otelarrow.go index 94162fb6..0b81dc30 100644 --- a/collector/receiver/otelarrowreceiver/otelarrow.go +++ b/collector/receiver/otelarrowreceiver/otelarrow.go @@ -114,7 +114,7 @@ func (r *otelArrowReceiver) startProtocolServers(host component.Host) error { return err } } - bq := admission.NewBoundedQueue(int64(r.cfg.Arrow.MemoryLimitMiB<<20), r.cfg.Arrow.WaiterLimit) + bq := admission.NewBoundedQueue(int64(r.cfg.Arrow.AdmissionLimitMiB<<20), r.cfg.Arrow.WaiterLimit) r.arrowReceiver, err = arrow.New(arrow.Consumers(r), r.settings, r.obsrepGRPC, r.cfg.GRPC, authServer, func() arrowRecord.ConsumerAPI { var opts []arrowRecord.Option From 8e162550a3117de2b2fd72ef979ea1c7b308abe2 Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Thu, 18 Apr 2024 05:46:14 -0400 Subject: [PATCH 04/28] closer to working --- collector/examples/bridge/edge-collector.yaml | 4 + .../receiver/otelarrowreceiver/factory.go | 1 + .../otelarrowreceiver/internal/arrow/arrow.go | 132 ++++++++++++------ 3 files changed, 98 insertions(+), 39 deletions(-) diff --git a/collector/examples/bridge/edge-collector.yaml b/collector/examples/bridge/edge-collector.yaml index d2f7e6d0..7dcc7be5 100644 --- a/collector/examples/bridge/edge-collector.yaml +++ b/collector/examples/bridge/edge-collector.yaml @@ -32,6 +32,10 @@ exporters: tls: insecure: true # headers: + # "lightstep-org-id": "2" + # "lightstep-org-name": "LightStep" + # "lightstep-project-id": "768070" + # "lightstep-project-name": "dev-mohosman" # lightstep-access-token: "${LIGHTSTEP_ACCESS_TOKEN}" # otelarrow/arrowout sends standard OTal Arrow to an external destination diff --git a/collector/receiver/otelarrowreceiver/factory.go b/collector/receiver/otelarrowreceiver/factory.go index 4b190684..e2a8cd78 100644 --- a/collector/receiver/otelarrowreceiver/factory.go +++ b/collector/receiver/otelarrowreceiver/factory.go @@ -46,6 +46,7 @@ func createDefaultConfig() component.Config { }, Arrow: ArrowConfig{ MemoryLimitMiB: defaultMemoryLimitMiB, + // AdmissionLimitMiB: defaultMemoryLimitMiB/2, }, }, } diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go index 59a8e427..339f8b67 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go @@ -8,7 +8,9 @@ import ( "errors" "fmt" "io" + "runtime" "strings" + "sync" arrowpb "github.com/open-telemetry/otel-arrow/api/experimental/arrow/v1" "github.com/open-telemetry/otel-arrow/collector/netstats" @@ -78,6 +80,8 @@ type Receiver struct { recvInFlightItems metric.Int64UpDownCounter recvInFlightRequests metric.Int64UpDownCounter boundedQueue *admission.BoundedQueue + inFlightWG sync.WaitGroup + pendingCh chan batchResp } // New creates a new Receiver reference. @@ -334,10 +338,15 @@ type anyStreamServer interface { grpc.ServerStream } +type batchResp struct { + id int64 + err error + uncompSz int64 +} + func (r *Receiver) anyStream(serverStream anyStreamServer, method string) (retErr error) { streamCtx := serverStream.Context() ac := r.newConsumer() - hrcv := newHeaderReceiver(serverStream.Context(), r.authServer, r.gsettings.IncludeMetadata) defer func() { if err := recover(); err != nil { @@ -355,12 +364,40 @@ func (r *Receiver) anyStream(serverStream anyStreamServer, method string) (retEr } }() + doneCtx, doneCancel := context.WithCancel(streamCtx) + streamErrCh := make(chan error, 1) + pendingCh := make(chan batchResp, runtime.NumCPU()) + + go r.srvReceiveLoop(doneCtx, serverStream, streamErrCh, pendingCh, method, ac) + + go r.srvSendLoop(doneCtx, serverStream, streamErrCh, pendingCh) + + select { + case <-doneCtx.Done(): + r.inFlightWG.Wait() + close(pendingCh) + return doneCtx.Err() + case retErr = <-streamErrCh: + doneCancel() + r.inFlightWG.Wait() + close(pendingCh) + return + } +} + +func (r *Receiver) srvReceiveLoop(ctx context.Context, serverStream anyStreamServer, streamErrCh chan<- error, pendingCh chan<- batchResp, method string, ac arrowRecord.ConsumerAPI) { + hrcv := newHeaderReceiver(ctx, r.authServer, r.gsettings.IncludeMetadata) for { + select { + case <-ctx.Done(): + return + default: + } + // Receive a batch corresponding with one ptrace.Traces, pmetric.Metrics, // or plog.Logs item. req, err := serverStream.Recv() - if err != nil { // This includes the case where a client called CloseSend(), in // which case we see an EOF error here. @@ -378,18 +415,20 @@ func (r *Receiver) anyStream(serverStream anyStreamServer, method string) (retEr // bounded queue to memory limit based on incoming uncompressed request size and waiters. // Acquire will fail immediately if there are too many waiters, // or will otherwise block until timeout or enough memory becomes available. - err = r.boundedQueue.Acquire(streamCtx, uncompSz) + err = r.boundedQueue.Acquire(ctx, uncompSz) if err != nil { r.logStreamError(err) - return err + streamErrCh <- err + return } // Check for optional headers and set the incoming context. - thisCtx, authHdrs, err := hrcv.combineHeaders(streamCtx, req.GetHeaders()) + thisCtx, authHdrs, err := hrcv.combineHeaders(ctx, req.GetHeaders()) if err != nil { // Failing to parse the incoming headers breaks the stream. r.telemetry.Logger.Error("arrow metadata error", zap.Error(err)) - return err + streamErrCh <- err + return } var authErr error @@ -402,15 +441,51 @@ func (r *Receiver) anyStream(serverStream anyStreamServer, method string) (retEr } } - if err := r.processAndConsume(thisCtx, method, ac, req, serverStream, authErr); err != nil { - return err + // this waitgroup will be incremented every time a request is received + // and decremented every time a response is sent. + r.inFlightWG.Add(1) + + // processAndConsume will process and send an error to the sender loop + go r.processAndConsume(thisCtx, method, ac, req, serverStream, authErr, pendingCh) + } +} + +func (r *Receiver) srvSendLoop(ctx context.Context, serverStream anyStreamServer, streamErrCh chan<- error, pendingCh <-chan batchResp) { + var err error + for resp := range pendingCh { + // Note: Statuses can be batched, but we do not take + // advantage of this feature. + status := &arrowpb.BatchStatus{ + BatchId: resp.id, + } + if resp.err == nil { + status.StatusCode = arrowpb.StatusCode_OK + } else { + status.StatusMessage = resp.err.Error() + switch { + case errors.Is(resp.err, arrowRecord.ErrConsumerMemoryLimit): + r.telemetry.Logger.Error("arrow resource exhausted", zap.Error(resp.err)) + status.StatusCode = arrowpb.StatusCode_RESOURCE_EXHAUSTED + case consumererror.IsPermanent(resp.err): + r.telemetry.Logger.Error("arrow data error", zap.Error(resp.err)) + status.StatusCode = arrowpb.StatusCode_INVALID_ARGUMENT + default: + r.telemetry.Logger.Debug("arrow consumer error", zap.Error(resp.err)) + status.StatusCode = arrowpb.StatusCode_UNAVAILABLE + } } - r.boundedQueue.Release(uncompSz) + err = serverStream.Send(status) + if err != nil { + r.logStreamError(err) + streamErrCh <- err + } + r.inFlightWG.Done() + r.boundedQueue.Release(resp.uncompSz) } } -func (r *Receiver) processAndConsume(ctx context.Context, method string, arrowConsumer arrowRecord.ConsumerAPI, req *arrowpb.BatchArrowRecords, serverStream anyStreamServer, authErr error) (retErr error) { +func (r *Receiver) processAndConsume(ctx context.Context, method string, arrowConsumer arrowRecord.ConsumerAPI, req *arrowpb.BatchArrowRecords, serverStream anyStreamServer, authErr error, pendingCh chan<- batchResp) { var err error ctx, span := r.tracer.Start(ctx, "otel_arrow_stream_recv") @@ -420,9 +495,9 @@ func (r *Receiver) processAndConsume(ctx context.Context, method string, arrowCo defer func() { r.recvInFlightRequests.Add(ctx, -1) // Set span status if an error is returned. - if retErr != nil { + if err != nil { span := trace.SpanFromContext(ctx) - span.SetStatus(otelcodes.Error, retErr.Error()) + span.SetStatus(otelcodes.Error, err.Error()) } }() @@ -434,34 +509,13 @@ func (r *Receiver) processAndConsume(ctx context.Context, method string, arrowCo err = r.processRecords(ctx, method, arrowConsumer, req) } - // Note: Statuses can be batched, but we do not take - // advantage of this feature. - status := &arrowpb.BatchStatus{ - BatchId: req.GetBatchId(), - } - if err == nil { - status.StatusCode = arrowpb.StatusCode_OK - } else { - status.StatusMessage = err.Error() - switch { - case errors.Is(err, arrowRecord.ErrConsumerMemoryLimit): - r.telemetry.Logger.Error("arrow resource exhausted", zap.Error(err)) - status.StatusCode = arrowpb.StatusCode_RESOURCE_EXHAUSTED - case consumererror.IsPermanent(err): - r.telemetry.Logger.Error("arrow data error", zap.Error(err)) - status.StatusCode = arrowpb.StatusCode_INVALID_ARGUMENT - default: - r.telemetry.Logger.Debug("arrow consumer error", zap.Error(err)) - status.StatusCode = arrowpb.StatusCode_UNAVAILABLE - } - } - - err = serverStream.Send(status) - if err != nil { - r.logStreamError(err) - return err + fmt.Println("BATCH ID") + fmt.Println(req.GetBatchId()) + pendingCh <- batchResp{ + id: req.GetBatchId(), + err: err, + uncompSz: int64(req.GetUncompressedSize()), } - return nil } // processRecords returns an error and a boolean indicating whether From 2a3fa37ef02329a6a978cd0df58f50d93ff5909e Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Tue, 23 Apr 2024 06:26:14 -0400 Subject: [PATCH 05/28] return error in goroutine --- collector/examples/bridge/edge-collector.yaml | 10 ++--- .../otelarrowreceiver/internal/arrow/arrow.go | 37 ++++++++++++------- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/collector/examples/bridge/edge-collector.yaml b/collector/examples/bridge/edge-collector.yaml index 7dcc7be5..7daa6ebe 100644 --- a/collector/examples/bridge/edge-collector.yaml +++ b/collector/examples/bridge/edge-collector.yaml @@ -31,11 +31,11 @@ exporters: disable_downgrade: true tls: insecure: true - # headers: - # "lightstep-org-id": "2" - # "lightstep-org-name": "LightStep" - # "lightstep-project-id": "768070" - # "lightstep-project-name": "dev-mohosman" + headers: + "lightstep-org-id": "2" + "lightstep-org-name": "LightStep" + "lightstep-project-id": "768070" + "lightstep-project-name": "dev-mohosman" # lightstep-access-token: "${LIGHTSTEP_ACCESS_TOKEN}" # otelarrow/arrowout sends standard OTal Arrow to an external destination diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go index 339f8b67..ec81f1a8 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go @@ -368,24 +368,34 @@ func (r *Receiver) anyStream(serverStream anyStreamServer, method string) (retEr streamErrCh := make(chan error, 1) pendingCh := make(chan batchResp, runtime.NumCPU()) - go r.srvReceiveLoop(doneCtx, serverStream, streamErrCh, pendingCh, method, ac) + go func() { + err := r.srvReceiveLoop(doneCtx, serverStream, streamErrCh, pendingCh, method, ac) + // if err != nil { + // // flush sender + // r.inFlightWG.Wait() + // } + streamErrCh <- err + } + + go func() { + err := r.srvSendLoop(doneCtx, serverStream, pendingCh) + streamErrCh <- err + } - go r.srvSendLoop(doneCtx, serverStream, streamErrCh, pendingCh) select { case <-doneCtx.Done(): - r.inFlightWG.Wait() - close(pendingCh) + // r.inFlightWG.Wait() + // close(pendingCh) return doneCtx.Err() case retErr = <-streamErrCh: doneCancel() - r.inFlightWG.Wait() - close(pendingCh) + // close(pendingCh) return } } -func (r *Receiver) srvReceiveLoop(ctx context.Context, serverStream anyStreamServer, streamErrCh chan<- error, pendingCh chan<- batchResp, method string, ac arrowRecord.ConsumerAPI) { +func (r *Receiver) srvReceiveLoop(ctx context.Context, serverStream anyStreamServer, streamErrCh chan<- error, pendingCh chan<- batchResp, method string, ac arrowRecord.ConsumerAPI) error { hrcv := newHeaderReceiver(ctx, r.authServer, r.gsettings.IncludeMetadata) for { select { @@ -418,8 +428,10 @@ func (r *Receiver) srvReceiveLoop(ctx context.Context, serverStream anyStreamSer err = r.boundedQueue.Acquire(ctx, uncompSz) if err != nil { r.logStreamError(err) - streamErrCh <- err - return + // TODO: Acquire will fail due to "too many waiters" or "context canceled" + // so we can log error and continue in hopes we have for the next request. + // This means this request will not be processed and will be dropped. + continue } // Check for optional headers and set the incoming context. @@ -427,8 +439,7 @@ func (r *Receiver) srvReceiveLoop(ctx context.Context, serverStream anyStreamSer if err != nil { // Failing to parse the incoming headers breaks the stream. r.telemetry.Logger.Error("arrow metadata error", zap.Error(err)) - streamErrCh <- err - return + return err } var authErr error @@ -450,7 +461,7 @@ func (r *Receiver) srvReceiveLoop(ctx context.Context, serverStream anyStreamSer } } -func (r *Receiver) srvSendLoop(ctx context.Context, serverStream anyStreamServer, streamErrCh chan<- error, pendingCh <-chan batchResp) { +func (r *Receiver) srvSendLoop(serverStream anyStreamServer, pendingCh <-chan batchResp) error { var err error for resp := range pendingCh { // Note: Statuses can be batched, but we do not take @@ -478,7 +489,7 @@ func (r *Receiver) srvSendLoop(ctx context.Context, serverStream anyStreamServer err = serverStream.Send(status) if err != nil { r.logStreamError(err) - streamErrCh <- err + return err } r.inFlightWG.Done() r.boundedQueue.Release(resp.uncompSz) From 45f2f9ac4ac987172cb5e462f39369ee0243858f Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Tue, 23 Apr 2024 08:04:33 -0400 Subject: [PATCH 06/28] refactor solve race, broken tests still --- .../otelarrowreceiver/internal/arrow/arrow.go | 79 +++++++++++++------ 1 file changed, 56 insertions(+), 23 deletions(-) diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go index ec81f1a8..bf473780 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go @@ -370,40 +370,37 @@ func (r *Receiver) anyStream(serverStream anyStreamServer, method string) (retEr go func() { err := r.srvReceiveLoop(doneCtx, serverStream, streamErrCh, pendingCh, method, ac) - // if err != nil { - // // flush sender - // r.inFlightWG.Wait() - // } streamErrCh <- err - } + }() go func() { err := r.srvSendLoop(doneCtx, serverStream, pendingCh) streamErrCh <- err - } + }() select { case <-doneCtx.Done(): - // r.inFlightWG.Wait() - // close(pendingCh) return doneCtx.Err() case retErr = <-streamErrCh: doneCancel() - // close(pendingCh) return } } -func (r *Receiver) srvReceiveLoop(ctx context.Context, serverStream anyStreamServer, streamErrCh chan<- error, pendingCh chan<- batchResp, method string, ac arrowRecord.ConsumerAPI) error { +func (r *Receiver) srvReceiveLoop(ctx context.Context, serverStream anyStreamServer, streamErrCh chan<- error, pendingCh chan<- batchResp, method string, ac arrowRecord.ConsumerAPI) (retErr error) { hrcv := newHeaderReceiver(ctx, r.authServer, r.gsettings.IncludeMetadata) for { select { case <-ctx.Done(): - return + return ctx.Err() default: } + // increment waitgroup before receive because if context is canceled, + // then there is potentially a race between r.flushSender and this in-flight request. + r.inFlightWG.Add(1) + // Receive a batch corresponding with one ptrace.Traces, pmetric.Metrics, // or plog.Logs item. req, err := serverStream.Recv() @@ -427,9 +424,10 @@ func (r *Receiver) srvReceiveLoop(ctx context.Context, serverStream anyStreamSer // or will otherwise block until timeout or enough memory becomes available. err = r.boundedQueue.Acquire(ctx, uncompSz) if err != nil { + r.inFlightWG.Done() // not processed r.logStreamError(err) - // TODO: Acquire will fail due to "too many waiters" or "context canceled" - // so we can log error and continue in hopes we have for the next request. + // Acquire will fail due to "too many waiters" or "context canceled" + // so we can log error and continue in hopes we can process the next request. // This means this request will not be processed and will be dropped. continue } @@ -437,6 +435,8 @@ func (r *Receiver) srvReceiveLoop(ctx context.Context, serverStream anyStreamSer // Check for optional headers and set the incoming context. thisCtx, authHdrs, err := hrcv.combineHeaders(ctx, req.GetHeaders()) if err != nil { + r.inFlightWG.Done() // not processed + // Failing to parse the incoming headers breaks the stream. r.telemetry.Logger.Error("arrow metadata error", zap.Error(err)) return err @@ -452,18 +452,15 @@ func (r *Receiver) srvReceiveLoop(ctx context.Context, serverStream anyStreamSer } } - // this waitgroup will be incremented every time a request is received - // and decremented every time a response is sent. - r.inFlightWG.Add(1) - // processAndConsume will process and send an error to the sender loop - go r.processAndConsume(thisCtx, method, ac, req, serverStream, authErr, pendingCh) + go func() { + r.processAndConsume(thisCtx, method, ac, req, serverStream, authErr, pendingCh) + r.inFlightWG.Done() // done processing + }() } } -func (r *Receiver) srvSendLoop(serverStream anyStreamServer, pendingCh <-chan batchResp) error { - var err error - for resp := range pendingCh { +func (r *Receiver) sendOne(serverStream anyStreamServer, resp batchResp) error { // Note: Statuses can be batched, but we do not take // advantage of this feature. status := &arrowpb.BatchStatus{ @@ -486,13 +483,49 @@ func (r *Receiver) srvSendLoop(serverStream anyStreamServer, pendingCh <-chan ba } } - err = serverStream.Send(status) + err := serverStream.Send(status) if err != nil { r.logStreamError(err) return err } - r.inFlightWG.Done() r.boundedQueue.Release(resp.uncompSz) + + return nil +} + +func (r *Receiver) flushSender(serverStream anyStreamServer, pendingCh <-chan batchResp) error { + var err error + // wait for all in flight requests to successfully be processed or fail. + r.inFlightWG.Wait() + for { + select { + case resp := <-pendingCh: + err = r.sendOne(serverStream, resp) + if err != nil { + return err + } + default: + // Currently nothing left in pendingCh. + return nil + } + } + +} + +func (r *Receiver) srvSendLoop(ctx context.Context, serverStream anyStreamServer, pendingCh <-chan batchResp) error { + var err error + for { + select { + case <-ctx.Done(): + err = r.flushSender(serverStream, pendingCh) + err := multierr.Append(err, ctx.Err()) + return err + case resp := <-pendingCh: + err = r.sendOne(serverStream, resp) + if err != nil { + return err + } + } } } From 3e68d50da0617d0aa336f4d8c1783fb730ec8720 Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Wed, 24 Apr 2024 17:17:23 -0400 Subject: [PATCH 07/28] almost --- .../otelarrowreceiver/internal/arrow/arrow.go | 30 ++++++++++++++----- .../internal/arrow/arrow_test.go | 6 ++++ 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go index bf473780..2105bcfa 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go @@ -11,6 +11,7 @@ import ( "runtime" "strings" "sync" + // "time arrowpb "github.com/open-telemetry/otel-arrow/api/experimental/arrow/v1" "github.com/open-telemetry/otel-arrow/collector/netstats" @@ -365,25 +366,35 @@ func (r *Receiver) anyStream(serverStream anyStreamServer, method string) (retEr }() doneCtx, doneCancel := context.WithCancel(streamCtx) - streamErrCh := make(chan error, 1) + streamErrCh := make(chan error, 2) pendingCh := make(chan batchResp, runtime.NumCPU()) + var wg sync.WaitGroup + // wg.Add(1) go func() { err := r.srvReceiveLoop(doneCtx, serverStream, streamErrCh, pendingCh, method, ac) streamErrCh <- err + // wg.Done() }() + wg.Add(1) go func() { err := r.srvSendLoop(doneCtx, serverStream, pendingCh) streamErrCh <- err + wg.Done() }() + // time.Sleep(3*time.Second) select { case <-doneCtx.Done(): + wg.Wait() + // r.inFlightWG.Wait() return doneCtx.Err() case retErr = <-streamErrCh: doneCancel() + // r.inFlightWG.Wait() + wg.Wait() return } } @@ -397,9 +408,6 @@ func (r *Receiver) srvReceiveLoop(ctx context.Context, serverStream anyStreamSer default: } - // increment waitgroup before receive because if context is canceled, - // then there is potentially a race between r.flushSender and this in-flight request. - r.inFlightWG.Add(1) // Receive a batch corresponding with one ptrace.Traces, pmetric.Metrics, // or plog.Logs item. @@ -417,6 +425,8 @@ func (r *Receiver) srvReceiveLoop(ctx context.Context, serverStream anyStreamSer } return err } + // there is potentially a race between r.flushSender and this in-flight request. + r.inFlightWG.Add(1) uncompSz := int64(req.GetUncompressedSize()) // bounded queue to memory limit based on incoming uncompressed request size and waiters. @@ -466,6 +476,8 @@ func (r *Receiver) sendOne(serverStream anyStreamServer, resp batchResp) error { status := &arrowpb.BatchStatus{ BatchId: resp.id, } + fmt.Println("SENDONE ERR") + fmt.Println(resp.err) if resp.err == nil { status.StatusCode = arrowpb.StatusCode_OK } else { @@ -518,7 +530,7 @@ func (r *Receiver) srvSendLoop(ctx context.Context, serverStream anyStreamServer select { case <-ctx.Done(): err = r.flushSender(serverStream, pendingCh) - err := multierr.Append(err, ctx.Err()) + // err := multierr.Append(err, ctx.Err()) return err case resp := <-pendingCh: err = r.sendOne(serverStream, resp) @@ -551,10 +563,12 @@ func (r *Receiver) processAndConsume(ctx context.Context, method string, arrowCo err = authErr } else { err = r.processRecords(ctx, method, arrowConsumer, req) + fmt.Println("PROCESS ERR") + fmt.Println(err) } - - fmt.Println("BATCH ID") - fmt.Println(req.GetBatchId()) +// + // fmt.Println("BATCH ID") + // fmt.Println(req.GetBatchId()) pendingCh <- batchResp{ id: req.GetBatchId(), err: err, diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go index a2e66016..f6bae446 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go @@ -580,6 +580,8 @@ func TestReceiverMemoryLimit(t *testing.T) { require.NoError(t, err) batch = copyBatch(batch) + fmt.Println("BATCH IDInTest") + fmt.Println(batch.BatchId) ctc.stream.EXPECT().Send(statusExhaustedFor(batch.BatchId, "Permanent error: test oom error "+arrowRecord.ErrConsumerMemoryLimit.Error())).Times(1).Return(nil) @@ -1065,6 +1067,8 @@ func testReceiverAuthHeaders(t *testing.T, includeMeta bool, dataAuth bool) { return ctx, nil } + fmt.Println(hdrs) + ok := false for _, val := range hdrs["auth"] { ok = ok || (val == "true") @@ -1172,6 +1176,8 @@ func testReceiverAuthHeaders(t *testing.T, includeMeta bool, dataAuth bool) { if expectErrs[idx] { require.NotEqual(t, arrowpb.StatusCode_OK, batch.StatusCode) } else { + fmt.Println("STATUS MSG") + fmt.Println(batch.StatusCode) require.Equal(t, arrowpb.StatusCode_OK, batch.StatusCode) } } From 212fca938c55695ca50cb9d1f3f4dfb9200a8afa Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Thu, 25 Apr 2024 07:58:05 -0400 Subject: [PATCH 08/28] painful but fixed? --- .../otelarrowreceiver/internal/arrow/arrow.go | 33 +++++++++++++------ .../internal/arrow/arrow_test.go | 6 ---- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go index 2105bcfa..f02dbeaa 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go @@ -11,7 +11,6 @@ import ( "runtime" "strings" "sync" - // "time arrowpb "github.com/open-telemetry/otel-arrow/api/experimental/arrow/v1" "github.com/open-telemetry/otel-arrow/collector/netstats" @@ -83,6 +82,7 @@ type Receiver struct { boundedQueue *admission.BoundedQueue inFlightWG sync.WaitGroup pendingCh chan batchResp + closecanceled bool } // New creates a new Receiver reference. @@ -385,7 +385,6 @@ func (r *Receiver) anyStream(serverStream anyStreamServer, method string) (retEr }() - // time.Sleep(3*time.Second) select { case <-doneCtx.Done(): wg.Wait() @@ -414,8 +413,17 @@ func (r *Receiver) srvReceiveLoop(ctx context.Context, serverStream anyStreamSer req, err := serverStream.Recv() if err != nil { +<<<<<<< HEAD // This includes the case where a client called CloseSend(), in // which case we see an EOF error here. +======= + // client called CloseSend() + if errors.Is(err, io.EOF) { + r.closecanceled = true + return nil + } + +>>>>>>> 348bb99 (painful but fixed?) r.logStreamError(err) if errors.Is(err, io.EOF) { @@ -473,11 +481,10 @@ func (r *Receiver) srvReceiveLoop(ctx context.Context, serverStream anyStreamSer func (r *Receiver) sendOne(serverStream anyStreamServer, resp batchResp) error { // Note: Statuses can be batched, but we do not take // advantage of this feature. + status := &arrowpb.BatchStatus{ BatchId: resp.id, } - fmt.Println("SENDONE ERR") - fmt.Println(resp.err) if resp.err == nil { status.StatusCode = arrowpb.StatusCode_OK } else { @@ -517,9 +524,20 @@ func (r *Receiver) flushSender(serverStream anyStreamServer, pendingCh <-chan ba return err } default: - // Currently nothing left in pendingCh. + // Currently nothing left in pendingCh. If canceled, make sure this + // status message is sent last. + if r.closecanceled { + status := &arrowpb.BatchStatus{} + status.StatusCode = arrowpb.StatusCode_CANCELED + err = serverStream.Send(status) + if err != nil { + r.logStreamError(err) + return err + } + } return nil } + } } @@ -563,12 +581,7 @@ func (r *Receiver) processAndConsume(ctx context.Context, method string, arrowCo err = authErr } else { err = r.processRecords(ctx, method, arrowConsumer, req) - fmt.Println("PROCESS ERR") - fmt.Println(err) } -// - // fmt.Println("BATCH ID") - // fmt.Println(req.GetBatchId()) pendingCh <- batchResp{ id: req.GetBatchId(), err: err, diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go index f6bae446..a2e66016 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go @@ -580,8 +580,6 @@ func TestReceiverMemoryLimit(t *testing.T) { require.NoError(t, err) batch = copyBatch(batch) - fmt.Println("BATCH IDInTest") - fmt.Println(batch.BatchId) ctc.stream.EXPECT().Send(statusExhaustedFor(batch.BatchId, "Permanent error: test oom error "+arrowRecord.ErrConsumerMemoryLimit.Error())).Times(1).Return(nil) @@ -1067,8 +1065,6 @@ func testReceiverAuthHeaders(t *testing.T, includeMeta bool, dataAuth bool) { return ctx, nil } - fmt.Println(hdrs) - ok := false for _, val := range hdrs["auth"] { ok = ok || (val == "true") @@ -1176,8 +1172,6 @@ func testReceiverAuthHeaders(t *testing.T, includeMeta bool, dataAuth bool) { if expectErrs[idx] { require.NotEqual(t, arrowpb.StatusCode_OK, batch.StatusCode) } else { - fmt.Println("STATUS MSG") - fmt.Println(batch.StatusCode) require.Equal(t, arrowpb.StatusCode_OK, batch.StatusCode) } } From 0d9f1809e4b4e9249b5558024ee4e28e7b662ee2 Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Thu, 25 Apr 2024 08:33:18 -0400 Subject: [PATCH 09/28] rm --- .../receiver/otelarrowreceiver/internal/arrow/arrow.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go index f02dbeaa..b8f84f0b 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go @@ -369,14 +369,13 @@ func (r *Receiver) anyStream(serverStream anyStreamServer, method string) (retEr streamErrCh := make(chan error, 2) pendingCh := make(chan batchResp, runtime.NumCPU()) - var wg sync.WaitGroup - // wg.Add(1) go func() { err := r.srvReceiveLoop(doneCtx, serverStream, streamErrCh, pendingCh, method, ac) streamErrCh <- err - // wg.Done() }() + // WG is used to ensure main thread only returns once sender is finished flushing all requests. + var wg sync.WaitGroup wg.Add(1) go func() { err := r.srvSendLoop(doneCtx, serverStream, pendingCh) @@ -388,11 +387,9 @@ func (r *Receiver) anyStream(serverStream anyStreamServer, method string) (retEr select { case <-doneCtx.Done(): wg.Wait() - // r.inFlightWG.Wait() return doneCtx.Err() case retErr = <-streamErrCh: doneCancel() - // r.inFlightWG.Wait() wg.Wait() return } From 366936e8b05c4977f0ee0e1eea4cf0671d6d1e31 Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Thu, 25 Apr 2024 09:59:04 -0400 Subject: [PATCH 10/28] rebase and fix tests again --- .../internal/arrow/exporter.go | 22 +++++++++---------- collector/go.sum | 7 ------ collector/receiver/otelarrowreceiver/go.mod | 6 +++++ collector/receiver/otelarrowreceiver/go.sum | 11 ++++++++-- .../otelarrowreceiver/internal/arrow/arrow.go | 17 +++++--------- .../internal/arrow/arrow_test.go | 3 +++ 6 files changed, 34 insertions(+), 32 deletions(-) diff --git a/collector/exporter/otelarrowexporter/internal/arrow/exporter.go b/collector/exporter/otelarrowexporter/internal/arrow/exporter.go index 0d80fb02..940f3443 100644 --- a/collector/exporter/otelarrowexporter/internal/arrow/exporter.go +++ b/collector/exporter/otelarrowexporter/internal/arrow/exporter.go @@ -285,18 +285,16 @@ func (e *Exporter) SendAndWait(ctx context.Context, data any) (bool, error) { // exporter, because of the optimization phase performed in the // conversion to Arrow. var uncompSize int - if e.telemetry.MetricsLevel > configtelemetry.LevelNormal { - switch data := data.(type) { - case ptrace.Traces: - var sizer ptrace.ProtoMarshaler - uncompSize = sizer.TracesSize(data) - case plog.Logs: - var sizer plog.ProtoMarshaler - uncompSize = sizer.LogsSize(data) - case pmetric.Metrics: - var sizer pmetric.ProtoMarshaler - uncompSize = sizer.MetricsSize(data) - } + switch data := data.(type) { + case ptrace.Traces: + var sizer ptrace.ProtoMarshaler + uncompSize = sizer.TracesSize(data) + case plog.Logs: + var sizer plog.ProtoMarshaler + uncompSize = sizer.LogsSize(data) + case pmetric.Metrics: + var sizer pmetric.ProtoMarshaler + uncompSize = sizer.MetricsSize(data) } wri := writeItem{ diff --git a/collector/go.sum b/collector/go.sum index 5521155f..982108ba 100644 --- a/collector/go.sum +++ b/collector/go.sum @@ -65,14 +65,8 @@ github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDN github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -<<<<<<< HEAD -======= -github.com/wk8/go-ordered-map v1.0.0 h1:BV7z+2PaK8LTSd/mWgY12HyMAo5CEgkHqbkVq2thqr8= -github.com/wk8/go-ordered-map v1.0.0/go.mod h1:9ZIbRunKbuvfPKyBP1SIKLcXNlv74YCOZ3t3VTS6gRk= ->>>>>>> 9668783 (add semaphore files) github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -149,6 +143,5 @@ google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHh gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/collector/receiver/otelarrowreceiver/go.mod b/collector/receiver/otelarrowreceiver/go.mod index 0fb7e0fa..1f03ab58 100644 --- a/collector/receiver/otelarrowreceiver/go.mod +++ b/collector/receiver/otelarrowreceiver/go.mod @@ -34,7 +34,9 @@ require ( github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect github.com/apache/arrow/go/v14 v14.0.2 // indirect github.com/axiomhq/hyperloglog v0.0.0-20230201085229-3ddf4bad03dc // indirect + github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/buger/jsonparser v1.1.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc // indirect @@ -55,6 +57,7 @@ require ( github.com/knadh/koanf/maps v0.1.1 // indirect github.com/knadh/koanf/providers/confmap v0.1.0 // indirect github.com/knadh/koanf/v2 v2.1.1 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -66,6 +69,7 @@ require ( github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.48.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect + github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect go.opentelemetry.io/collector/config/configcompression v1.5.0 // indirect @@ -87,3 +91,5 @@ require ( google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) + +replace github.com/open-telemetry/otel-arrow/collector v0.22.0 => ../../ diff --git a/collector/receiver/otelarrowreceiver/go.sum b/collector/receiver/otelarrowreceiver/go.sum index b337bb8e..a0285322 100644 --- a/collector/receiver/otelarrowreceiver/go.sum +++ b/collector/receiver/otelarrowreceiver/go.sum @@ -7,10 +7,14 @@ github.com/apache/arrow/go/v14 v14.0.2 h1:N8OkaJEOfI3mEZt07BIkvo4sC6XDbL+48MBPWO github.com/apache/arrow/go/v14 v14.0.2/go.mod h1:u3fgh3EdgN/YQ8cVQRguVW3R+seMybFg8QBQ5LU+eBY= github.com/axiomhq/hyperloglog v0.0.0-20230201085229-3ddf4bad03dc h1:Keo7wQ7UODUaHcEi7ltENhbAK2VgZjfat6mLy03tQzo= github.com/axiomhq/hyperloglog v0.0.0-20230201085229-3ddf4bad03dc/go.mod h1:k08r+Yj1PRAmuayFiRK6MYuR5Ve4IuZtTfxErMIh0+c= +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/brianvoe/gofakeit/v6 v6.17.0 h1:obbQTJeHfktJtiZzq0Q1bEpsNUs+yHrYlPVWt7BtmJ4= github.com/brianvoe/gofakeit/v6 v6.17.0/go.mod h1:Ow6qC71xtwm79anlwKRlWZW6zVq9D2XHE4QSSMP/rU8= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -49,6 +53,7 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= @@ -70,6 +75,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= @@ -84,8 +91,6 @@ github.com/mostynb/go-grpc-compression v1.2.2/go.mod h1:GOCr2KBxXcblCuczg3YdLQlc github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/open-telemetry/otel-arrow v0.22.0 h1:G1jgtqAM2ho5pyKQ4tyrDzk9Y0VcJ+GZQRJgN26vRlI= github.com/open-telemetry/otel-arrow v0.22.0/go.mod h1:F50XFaiNfkfB0MYftZIUKFULm6pxfGqjbgQzevi+65M= -github.com/open-telemetry/otel-arrow/collector v0.22.0 h1:lHFjzkh5PbsiW8B63SRntnP9W7bLCXV9lslO4zI0s/Y= -github.com/open-telemetry/otel-arrow/collector v0.22.0/go.mod h1:R7hRwuGDxoGLB27dkJUFKDK7mGG7Yb02ODnLHx8Whis= github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -105,6 +110,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= +github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go index b8f84f0b..1c94bcc9 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go @@ -387,7 +387,7 @@ func (r *Receiver) anyStream(serverStream anyStreamServer, method string) (retEr select { case <-doneCtx.Done(): wg.Wait() - return doneCtx.Err() + return status.Error(codes.Canceled, "server stream shutdown") case retErr = <-streamErrCh: doneCancel() wg.Wait() @@ -400,7 +400,7 @@ func (r *Receiver) srvReceiveLoop(ctx context.Context, serverStream anyStreamSer for { select { case <-ctx.Done(): - return ctx.Err() + return status.Error(codes.Canceled, "server stream shutdown") default: } @@ -410,17 +410,12 @@ func (r *Receiver) srvReceiveLoop(ctx context.Context, serverStream anyStreamSer req, err := serverStream.Recv() if err != nil { -<<<<<<< HEAD - // This includes the case where a client called CloseSend(), in - // which case we see an EOF error here. -======= // client called CloseSend() - if errors.Is(err, io.EOF) { - r.closecanceled = true - return nil - } + // if errors.Is(err, io.EOF) { + // r.closecanceled = true + // return nil + // } ->>>>>>> 348bb99 (painful but fixed?) r.logStreamError(err) if errors.Is(err, io.EOF) { diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go index a2e66016..82712892 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go @@ -357,6 +357,9 @@ func (ctc *commonTestCase) start(newConsumer func() arrowRecord.ConsumerAPI, opt func requireCanceledStatus(t *testing.T, err error) { require.Error(t, err) status, ok := status.FromError(err) + fmt.Println("STATUS OK") + fmt.Println(ok) + fmt.Println(status) require.True(t, ok, "is status-wrapped %v", err) require.Equal(t, codes.Canceled, status.Code()) } From 4c8429711ef90473b78f8712f9b7ceb13cc1fb6d Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Thu, 25 Apr 2024 12:08:51 -0400 Subject: [PATCH 11/28] fix race --- collector/examples/bridge/edge-collector.yaml | 92 +++++++------------ collector/examples/bridge/saas-collector.yaml | 59 +++++++++--- .../otelarrowreceiver/internal/arrow/arrow.go | 38 ++------ .../internal/arrow/arrow_test.go | 3 - 4 files changed, 89 insertions(+), 103 deletions(-) diff --git a/collector/examples/bridge/edge-collector.yaml b/collector/examples/bridge/edge-collector.yaml index 7daa6ebe..38b23240 100644 --- a/collector/examples/bridge/edge-collector.yaml +++ b/collector/examples/bridge/edge-collector.yaml @@ -1,76 +1,52 @@ receivers: - # otelarrow/stdin is for regular traffic on the default gRPC port - otelarrow/stdin: - protocols: - grpc: - endpoint: 127.0.0.1:4317 - # otelarrow/loopback receives OTel-Arrow traffic on port 8100 - otelarrow/loopback: - protocols: - grpc: - endpoint: 127.0.0.1:8100 - max_recv_msg_size_mib: 3000 + # otelarrow/standard is an OTelArrow receiver. + # it uses port 4317, the standard port for OTLP/gRPC. + # There are no required configuration fields. + otelarrow/standard: processors: + # The batch processor will benefit pipelines with small export sizes. concurrentbatch: - # the experiment processor routes 1 in 3 requests to the Arrow - # loopback exporter - experiment: - table: - - weight: 1 - exporters: [otelarrow/arrowout, logging/debug] - - weight: 2 - exporters: [otelarrow/stdout, logging/info] exporters: - # otelarrow/stdout sends OTel Arrow to an external destination - otelarrow/stdout: - endpoint: localhost:4317 - arrow: - disabled: false - disable_downgrade: true + # otelarrow/arrow is an OTel-Arrow exporter. + otelarrow/arrow: + # For the sample configuration, the other side of the bridge + # runs on port 8100. + endpoint: 127.0.0.1:8100 + + # For demonstration purposes, use an insecure port. This would + # also be normal for a collector behind a loadbalancer that + # terminates TLS. tls: insecure: true + + # Static headers will be attached to every export. headers: - "lightstep-org-id": "2" - "lightstep-org-name": "LightStep" - "lightstep-project-id": "768070" - "lightstep-project-name": "dev-mohosman" - # lightstep-access-token: "${LIGHTSTEP_ACCESS_TOKEN}" + - X-Scope-OrgID: example_tenant - # otelarrow/arrowout sends standard OTal Arrow to an external destination - otelarrow/arrowout: - endpoint: 127.0.0.1:8100 - # wait_for_ready ensures the exporter doesn't fallback to standard - # OTLP because the exporter has not started. + # wait_for_ready lets the producer block until the connection + # is ready. wait_for_ready: true - tls: - insecure: true - arrow: - num_streams: 1 - disable_downgrade: true - debug/info: - verbosity: normal - debug/debug: - verbosity: detailed + debug: service: pipelines: - # the normal traces pipeline either routes directly to the - # standard output or via the loopback. it prints an info. - # traces/normal: - # receivers: [otelarrow/stdin] - # processors: [concurrentbatch, experiment] - # exporters: [debug/info, otelarrow/stdout, otelarrow/arrowout] - - # experiment processes data send via Arrow through the loopback. - # it prints a debug log. - traces/experiment: - receivers: [otelarrow/loopback] - processors: [] - exporters: [debug/info, otelarrow/stdout] + traces: + receivers: [otelarrow/standard] + processors: [concurrentbatch] + exporters: [otelarrow/arrow, debug] + metrics: + receivers: [otelarrow/standard] + processors: [concurrentbatch] + exporters: [otelarrow/arrow, debug] telemetry: + resource: + "service.name": "example-bridge" metrics: - address: localhost:8888 \ No newline at end of file + address: 127.0.0.1:8888 + level: detailed + logs: + level: info \ No newline at end of file diff --git a/collector/examples/bridge/saas-collector.yaml b/collector/examples/bridge/saas-collector.yaml index cd626798..1bcbdd7c 100644 --- a/collector/examples/bridge/saas-collector.yaml +++ b/collector/examples/bridge/saas-collector.yaml @@ -1,27 +1,60 @@ receivers: + # otelarrow is an OTel Arrow receiver that will operate as the SaaS-side + # of the bridge. otelarrow: protocols: grpc: - endpoint: localhost:4317 - max_recv_msg_size_mib: 3000 - arrow: - admission_limit_mib: 30 - waiter_limit: 2 + # Port 5000 is the endpoint used in edge-collector. + endpoint: 127.0.0.1:8100 -processors: - concurrentbatch: + # Include metadata so that the exporter can copy it + # to the next hop. + include_metadata: true + + keepalive: + server_parameters: + max_connection_age: 10s + max_connection_age_grace: 10s exporters: - debug: - verbosity: basic - otelarrow/ls: - endpoint: ingest.lightstep.com:443 + debug: + + otlphttp: + # You can use an HTTP listener on port 5001 to see the headers + # and raw data. + endpoint: http://127.0.0.1:8101 + compression: none + + # Associate the headers_setter extension with this exporter + # so that it passes through headers set on the edge collector. + auth: + authenticator: headers_setter + +extensions: + # Configure the headers_setter extension to propagate the + # X-Scope-OrgID property in the outgoing context. + headers_setter: headers: - "lightstep-access-token": ${LS_TOKEN} + - key: X-Scope-OrgID + from_context: X-Scope-OrgID service: + extensions: [headers_setter] pipelines: traces: receivers: [otelarrow] + + # Note there is no need to re-apply the batch processor on the + # SaaS-side of a bridge. + processors: [] + exporters: [debug, otlphttp] + + metrics: + receivers: [otelarrow] processors: [] - exporters: [debug, otelarrow/ls] \ No newline at end of file + exporters: [debug, otlphttp] + + telemetry: + metrics: + address: 127.0.0.1:8889 + level: normal \ No newline at end of file diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go index 1c94bcc9..114456c5 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go @@ -82,7 +82,6 @@ type Receiver struct { boundedQueue *admission.BoundedQueue inFlightWG sync.WaitGroup pendingCh chan batchResp - closecanceled bool } // New creates a new Receiver reference. @@ -374,23 +373,23 @@ func (r *Receiver) anyStream(serverStream anyStreamServer, method string) (retEr streamErrCh <- err }() - // WG is used to ensure main thread only returns once sender is finished flushing all requests. - var wg sync.WaitGroup - wg.Add(1) + // WG is used to ensure main thread only returns once sender is finished sending responses for all requests. + var senderWG sync.WaitGroup + senderWG.Add(1) go func() { err := r.srvSendLoop(doneCtx, serverStream, pendingCh) streamErrCh <- err - wg.Done() + senderWG.Done() }() select { case <-doneCtx.Done(): - wg.Wait() + senderWG.Wait() return status.Error(codes.Canceled, "server stream shutdown") case retErr = <-streamErrCh: doneCancel() - wg.Wait() + senderWG.Wait() return } } @@ -402,20 +401,15 @@ func (r *Receiver) srvReceiveLoop(ctx context.Context, serverStream anyStreamSer case <-ctx.Done(): return status.Error(codes.Canceled, "server stream shutdown") default: + r.inFlightWG.Add(1) } - // Receive a batch corresponding with one ptrace.Traces, pmetric.Metrics, // or plog.Logs item. req, err := serverStream.Recv() if err != nil { - // client called CloseSend() - // if errors.Is(err, io.EOF) { - // r.closecanceled = true - // return nil - // } - + r.inFlightWG.Done() // not processed r.logStreamError(err) if errors.Is(err, io.EOF) { @@ -425,8 +419,6 @@ func (r *Receiver) srvReceiveLoop(ctx context.Context, serverStream anyStreamSer } return err } - // there is potentially a race between r.flushSender and this in-flight request. - r.inFlightWG.Add(1) uncompSz := int64(req.GetUncompressedSize()) // bounded queue to memory limit based on incoming uncompressed request size and waiters. @@ -516,22 +508,10 @@ func (r *Receiver) flushSender(serverStream anyStreamServer, pendingCh <-chan ba return err } default: - // Currently nothing left in pendingCh. If canceled, make sure this - // status message is sent last. - if r.closecanceled { - status := &arrowpb.BatchStatus{} - status.StatusCode = arrowpb.StatusCode_CANCELED - err = serverStream.Send(status) - if err != nil { - r.logStreamError(err) - return err - } - } + // Currently nothing left in pendingCh. return nil } - } - } func (r *Receiver) srvSendLoop(ctx context.Context, serverStream anyStreamServer, pendingCh <-chan batchResp) error { diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go index 82712892..a2e66016 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go @@ -357,9 +357,6 @@ func (ctc *commonTestCase) start(newConsumer func() arrowRecord.ConsumerAPI, opt func requireCanceledStatus(t *testing.T, err error) { require.Error(t, err) status, ok := status.FromError(err) - fmt.Println("STATUS OK") - fmt.Println(ok) - fmt.Println(status) require.True(t, ok, "is status-wrapped %v", err) require.Equal(t, codes.Canceled, status.Code()) } From e1b920a03a80dddb8a422876157990f26807bb3d Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Thu, 25 Apr 2024 12:15:39 -0400 Subject: [PATCH 12/28] remove unneded package --- collector/exporter/otelarrowexporter/internal/arrow/exporter.go | 1 - 1 file changed, 1 deletion(-) diff --git a/collector/exporter/otelarrowexporter/internal/arrow/exporter.go b/collector/exporter/otelarrowexporter/internal/arrow/exporter.go index 940f3443..aba9582e 100644 --- a/collector/exporter/otelarrowexporter/internal/arrow/exporter.go +++ b/collector/exporter/otelarrowexporter/internal/arrow/exporter.go @@ -14,7 +14,6 @@ import ( "github.com/open-telemetry/otel-arrow/collector/netstats" arrowRecord "github.com/open-telemetry/otel-arrow/pkg/otel/arrow_record" "go.opentelemetry.io/collector/component" - "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" From f93a37c31332c99bb1f466a9f29ff2dead1bd335 Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Thu, 25 Apr 2024 13:47:09 -0400 Subject: [PATCH 13/28] remove replace --- collector/exporter/otelarrowexporter/go.mod | 2 +- collector/receiver/otelarrowreceiver/go.mod | 6 ------ collector/receiver/otelarrowreceiver/go.sum | 10 +--------- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/collector/exporter/otelarrowexporter/go.mod b/collector/exporter/otelarrowexporter/go.mod index 1095729f..4a99cda6 100644 --- a/collector/exporter/otelarrowexporter/go.mod +++ b/collector/exporter/otelarrowexporter/go.mod @@ -16,7 +16,6 @@ require ( go.opentelemetry.io/collector/config/configgrpc v0.98.0 go.opentelemetry.io/collector/config/configopaque v1.5.0 go.opentelemetry.io/collector/config/configretry v0.98.0 - go.opentelemetry.io/collector/config/configtelemetry v0.98.0 go.opentelemetry.io/collector/config/configtls v0.98.0 go.opentelemetry.io/collector/confmap v0.98.0 go.opentelemetry.io/collector/consumer v0.98.0 @@ -75,6 +74,7 @@ require ( github.com/x448/float16 v0.8.4 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect go.opentelemetry.io/collector/config/confignet v0.98.0 // indirect + go.opentelemetry.io/collector/config/configtelemetry v0.98.0 // indirect go.opentelemetry.io/collector/config/internal v0.98.0 // indirect go.opentelemetry.io/collector/featuregate v1.5.0 // indirect go.opentelemetry.io/collector/receiver v0.98.0 // indirect diff --git a/collector/receiver/otelarrowreceiver/go.mod b/collector/receiver/otelarrowreceiver/go.mod index 1f03ab58..0fb7e0fa 100644 --- a/collector/receiver/otelarrowreceiver/go.mod +++ b/collector/receiver/otelarrowreceiver/go.mod @@ -34,9 +34,7 @@ require ( github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect github.com/apache/arrow/go/v14 v14.0.2 // indirect github.com/axiomhq/hyperloglog v0.0.0-20230201085229-3ddf4bad03dc // indirect - github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/buger/jsonparser v1.1.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc // indirect @@ -57,7 +55,6 @@ require ( github.com/knadh/koanf/maps v0.1.1 // indirect github.com/knadh/koanf/providers/confmap v0.1.0 // indirect github.com/knadh/koanf/v2 v2.1.1 // indirect - github.com/mailru/easyjson v0.7.7 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -69,7 +66,6 @@ require ( github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.48.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect - github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect go.opentelemetry.io/collector/config/configcompression v1.5.0 // indirect @@ -91,5 +87,3 @@ require ( google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) - -replace github.com/open-telemetry/otel-arrow/collector v0.22.0 => ../../ diff --git a/collector/receiver/otelarrowreceiver/go.sum b/collector/receiver/otelarrowreceiver/go.sum index a0285322..5446808e 100644 --- a/collector/receiver/otelarrowreceiver/go.sum +++ b/collector/receiver/otelarrowreceiver/go.sum @@ -7,14 +7,10 @@ github.com/apache/arrow/go/v14 v14.0.2 h1:N8OkaJEOfI3mEZt07BIkvo4sC6XDbL+48MBPWO github.com/apache/arrow/go/v14 v14.0.2/go.mod h1:u3fgh3EdgN/YQ8cVQRguVW3R+seMybFg8QBQ5LU+eBY= github.com/axiomhq/hyperloglog v0.0.0-20230201085229-3ddf4bad03dc h1:Keo7wQ7UODUaHcEi7ltENhbAK2VgZjfat6mLy03tQzo= github.com/axiomhq/hyperloglog v0.0.0-20230201085229-3ddf4bad03dc/go.mod h1:k08r+Yj1PRAmuayFiRK6MYuR5Ve4IuZtTfxErMIh0+c= -github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= -github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/brianvoe/gofakeit/v6 v6.17.0 h1:obbQTJeHfktJtiZzq0Q1bEpsNUs+yHrYlPVWt7BtmJ4= github.com/brianvoe/gofakeit/v6 v6.17.0/go.mod h1:Ow6qC71xtwm79anlwKRlWZW6zVq9D2XHE4QSSMP/rU8= -github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= -github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -53,7 +49,6 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= @@ -75,8 +70,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= @@ -91,6 +84,7 @@ github.com/mostynb/go-grpc-compression v1.2.2/go.mod h1:GOCr2KBxXcblCuczg3YdLQlc github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/open-telemetry/otel-arrow v0.22.0 h1:G1jgtqAM2ho5pyKQ4tyrDzk9Y0VcJ+GZQRJgN26vRlI= github.com/open-telemetry/otel-arrow v0.22.0/go.mod h1:F50XFaiNfkfB0MYftZIUKFULm6pxfGqjbgQzevi+65M= +github.com/open-telemetry/otel-arrow/collector v0.22.0 h1:lHFjzkh5PbsiW8B63SRntnP9W7bLCXV9lslO4zI0s/Y= github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -110,8 +104,6 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= -github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= From 77364fe45e3456851ca0b9b296b033505faddfd2 Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Fri, 26 Apr 2024 08:19:00 -0400 Subject: [PATCH 14/28] review feedback --- collector/receiver/otelarrowreceiver/go.mod | 4 + .../otelarrowreceiver/internal/arrow/arrow.go | 112 +++++++++--------- 2 files changed, 62 insertions(+), 54 deletions(-) diff --git a/collector/receiver/otelarrowreceiver/go.mod b/collector/receiver/otelarrowreceiver/go.mod index 0fb7e0fa..60abc223 100644 --- a/collector/receiver/otelarrowreceiver/go.mod +++ b/collector/receiver/otelarrowreceiver/go.mod @@ -34,7 +34,9 @@ require ( github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect github.com/apache/arrow/go/v14 v14.0.2 // indirect github.com/axiomhq/hyperloglog v0.0.0-20230201085229-3ddf4bad03dc // indirect + github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/buger/jsonparser v1.1.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc // indirect @@ -55,6 +57,7 @@ require ( github.com/knadh/koanf/maps v0.1.1 // indirect github.com/knadh/koanf/providers/confmap v0.1.0 // indirect github.com/knadh/koanf/v2 v2.1.1 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -66,6 +69,7 @@ require ( github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.48.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect + github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect go.opentelemetry.io/collector/config/configcompression v1.5.0 // indirect diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go index 114456c5..0f4457a8 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go @@ -394,71 +394,75 @@ func (r *Receiver) anyStream(serverStream anyStreamServer, method string) (retEr } } -func (r *Receiver) srvReceiveLoop(ctx context.Context, serverStream anyStreamServer, streamErrCh chan<- error, pendingCh chan<- batchResp, method string, ac arrowRecord.ConsumerAPI) (retErr error) { - hrcv := newHeaderReceiver(ctx, r.authServer, r.gsettings.IncludeMetadata) - for { - select { - case <-ctx.Done(): - return status.Error(codes.Canceled, "server stream shutdown") - default: - r.inFlightWG.Add(1) +func (r *Receiver) recvOne(ctx context.Context, serverStream anyStreamServer, hrcv *headerReceiver, pendingCh chan<- batchResp, method string, ac arrowRecord.ConsumerAPI) (retErr error) { + r.inFlightWG.Add(1) + defer func() { + if retErr != nil { + r.inFlightWG.Done() // not processed + r.logStreamError(retErr) } + }() - // Receive a batch corresponding with one ptrace.Traces, pmetric.Metrics, - // or plog.Logs item. - req, err := serverStream.Recv() + // Receive a batch corresponding with one ptrace.Traces, pmetric.Metrics, + // or plog.Logs item. + req, err := serverStream.Recv() - if err != nil { - r.inFlightWG.Done() // not processed - r.logStreamError(err) - - if errors.Is(err, io.EOF) { - return status.Error(codes.Canceled, "client stream shutdown") - } else if errors.Is(err, context.Canceled) { - return status.Error(codes.Canceled, "server stream shutdown") - } - return err + if err != nil { + if errors.Is(err, io.EOF) { + return status.Error(codes.Canceled, "client stream shutdown") + } else if errors.Is(err, context.Canceled) { + return status.Error(codes.Canceled, "server stream shutdown") } + return err + } - uncompSz := int64(req.GetUncompressedSize()) - // bounded queue to memory limit based on incoming uncompressed request size and waiters. - // Acquire will fail immediately if there are too many waiters, - // or will otherwise block until timeout or enough memory becomes available. - err = r.boundedQueue.Acquire(ctx, uncompSz) - if err != nil { - r.inFlightWG.Done() // not processed - r.logStreamError(err) - // Acquire will fail due to "too many waiters" or "context canceled" - // so we can log error and continue in hopes we can process the next request. - // This means this request will not be processed and will be dropped. - continue - } + uncompSz := int64(req.GetUncompressedSize()) + // bounded queue to memory limit based on incoming uncompressed request size and waiters. + // Acquire will fail immediately if there are too many waiters, + // or will otherwise block until timeout or enough memory becomes available. + err = r.boundedQueue.Acquire(ctx, uncompSz) + if err != nil { + return fmt.Errorf("breaking stream: %v", err) + } - // Check for optional headers and set the incoming context. - thisCtx, authHdrs, err := hrcv.combineHeaders(ctx, req.GetHeaders()) - if err != nil { - r.inFlightWG.Done() // not processed + // Check for optional headers and set the incoming context. + thisCtx, authHdrs, err := hrcv.combineHeaders(ctx, req.GetHeaders()) + if err != nil { + // Failing to parse the incoming headers breaks the stream. + return fmt.Errorf("arrow metadata error: %v", err) + } - // Failing to parse the incoming headers breaks the stream. - r.telemetry.Logger.Error("arrow metadata error", zap.Error(err)) - return err + var authErr error + if r.authServer != nil { + var newCtx context.Context + if newCtx, err = r.authServer.Authenticate(thisCtx, authHdrs); err != nil { + authErr = err + } else { + thisCtx = newCtx } + } + + // processAndConsume will process and send an error to the sender loop + go func() { + defer r.inFlightWG.Done() // done processing + r.processAndConsume(thisCtx, method, ac, req, serverStream, authErr, pendingCh) + }() + + return nil +} - var authErr error - if r.authServer != nil { - var newCtx context.Context - if newCtx, err = r.authServer.Authenticate(thisCtx, authHdrs); err != nil { - authErr = err - } else { - thisCtx = newCtx +func (r *Receiver) srvReceiveLoop(ctx context.Context, serverStream anyStreamServer, streamErrCh chan<- error, pendingCh chan<- batchResp, method string, ac arrowRecord.ConsumerAPI) (retErr error) { + hrcv := newHeaderReceiver(ctx, r.authServer, r.gsettings.IncludeMetadata) + for { + select { + case <-ctx.Done(): + return status.Error(codes.Canceled, "server stream shutdown") + default: + err := r.recvOne(ctx, serverStream, hrcv, pendingCh, method, ac) + if err != nil { + return err } } - - // processAndConsume will process and send an error to the sender loop - go func() { - r.processAndConsume(thisCtx, method, ac, req, serverStream, authErr, pendingCh) - r.inFlightWG.Done() // done processing - }() } } From a8448e4e7e08e7d0e28df4d49ed205e307b1246a Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Fri, 26 Apr 2024 09:01:08 -0400 Subject: [PATCH 15/28] remove unneeded arg --- collector/receiver/otelarrowreceiver/internal/arrow/arrow.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go index 0f4457a8..db93af38 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go @@ -369,7 +369,7 @@ func (r *Receiver) anyStream(serverStream anyStreamServer, method string) (retEr pendingCh := make(chan batchResp, runtime.NumCPU()) go func() { - err := r.srvReceiveLoop(doneCtx, serverStream, streamErrCh, pendingCh, method, ac) + err := r.srvReceiveLoop(doneCtx, serverStream, pendingCh, method, ac) streamErrCh <- err }() @@ -451,7 +451,7 @@ func (r *Receiver) recvOne(ctx context.Context, serverStream anyStreamServer, hr return nil } -func (r *Receiver) srvReceiveLoop(ctx context.Context, serverStream anyStreamServer, streamErrCh chan<- error, pendingCh chan<- batchResp, method string, ac arrowRecord.ConsumerAPI) (retErr error) { +func (r *Receiver) srvReceiveLoop(ctx context.Context, serverStream anyStreamServer, pendingCh chan<- batchResp, method string, ac arrowRecord.ConsumerAPI) (retErr error) { hrcv := newHeaderReceiver(ctx, r.authServer, r.gsettings.IncludeMetadata) for { select { From 12f1b8c81544781b82a0ae8544e9964ff3fc5850 Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Wed, 1 May 2024 08:31:59 -0400 Subject: [PATCH 16/28] rm uncompressed_size from proto --- api/experimental/arrow/v1/arrow_service.pb.go | 216 +++++++++--------- .../experimental/arrow/v1/arrow_service.proto | 3 - 2 files changed, 102 insertions(+), 117 deletions(-) diff --git a/api/experimental/arrow/v1/arrow_service.pb.go b/api/experimental/arrow/v1/arrow_service.pb.go index 95886685..693de228 100644 --- a/api/experimental/arrow/v1/arrow_service.pb.go +++ b/api/experimental/arrow/v1/arrow_service.pb.go @@ -249,8 +249,6 @@ type BatchArrowRecords struct { ArrowPayloads []*ArrowPayload `protobuf:"bytes,2,rep,name=arrow_payloads,json=arrowPayloads,proto3" json:"arrow_payloads,omitempty"` // [optional] Headers associated with this batch, encoded using hpack. Headers []byte `protobuf:"bytes,3,opt,name=headers,proto3" json:"headers,omitempty"` - // [mandatory] The uncompressed size of the batch. - UncompressedSize uint64 `protobuf:"varint,4,opt,name=uncompressed_size,json=uncompressedSize,proto3" json:"uncompressed_size,omitempty"` } func (x *BatchArrowRecords) Reset() { @@ -306,13 +304,6 @@ func (x *BatchArrowRecords) GetHeaders() []byte { return nil } -func (x *BatchArrowRecords) GetUncompressedSize() uint64 { - if x != nil { - return x.UncompressedSize - } - return 0 -} - // Represents a batch of OTel Arrow entities. type ArrowPayload struct { state protoimpl.MessageState @@ -461,7 +452,7 @@ var file_opentelemetry_proto_experimental_arrow_v1_arrow_service_proto_rawDesc = 0x77, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x29, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, - 0x6c, 0x2e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x22, 0xd5, 0x01, 0x0a, 0x11, 0x42, + 0x6c, 0x2e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x22, 0xa8, 0x01, 0x0a, 0x11, 0x42, 0x61, 0x74, 0x63, 0x68, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x62, 0x61, 0x74, 0x63, 0x68, 0x49, 0x64, 0x12, 0x5e, 0x0a, 0x0e, 0x61, @@ -472,115 +463,112 @@ var file_opentelemetry_proto_experimental_arrow_v1_arrow_service_proto_rawDesc = 0x41, 0x72, 0x72, 0x6f, 0x77, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x0d, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x68, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x75, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x64, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x10, 0x75, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x69, - 0x7a, 0x65, 0x22, 0x94, 0x01, 0x0a, 0x0c, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x50, 0x61, 0x79, 0x6c, - 0x6f, 0x61, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x49, 0x64, - 0x12, 0x4f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3b, - 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, - 0x6c, 0x2e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x72, 0x72, 0x6f, 0x77, - 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x22, 0xa7, 0x01, 0x0a, 0x0b, 0x42, 0x61, - 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x61, 0x74, - 0x63, 0x68, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x62, 0x61, 0x74, - 0x63, 0x68, 0x49, 0x64, 0x12, 0x56, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x63, - 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x35, 0x2e, 0x6f, 0x70, 0x65, 0x6e, - 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2e, 0x61, 0x72, 0x72, - 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, - 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x25, 0x0a, 0x0e, - 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x2a, 0xf9, 0x04, 0x0a, 0x10, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x50, 0x61, 0x79, - 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, - 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, - 0x45, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x43, 0x4f, - 0x50, 0x45, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x02, 0x12, 0x16, 0x0a, 0x12, 0x55, 0x4e, + 0x61, 0x64, 0x65, 0x72, 0x73, 0x22, 0x94, 0x01, 0x0a, 0x0c, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x50, + 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x63, 0x68, 0x65, 0x6d, + 0x61, 0x49, 0x64, 0x12, 0x4f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x3b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, + 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, + 0x6e, 0x74, 0x61, 0x6c, 0x2e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x72, + 0x72, 0x6f, 0x77, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x22, 0xa7, 0x01, 0x0a, + 0x0b, 0x42, 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x19, 0x0a, 0x08, + 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, + 0x62, 0x61, 0x74, 0x63, 0x68, 0x49, 0x64, 0x12, 0x56, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x35, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2e, + 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, + 0x6f, 0x64, 0x65, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x12, + 0x25, 0x0a, 0x0e, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2a, 0xf9, 0x04, 0x0a, 0x10, 0x41, 0x72, 0x72, 0x6f, 0x77, + 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, + 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x53, 0x4f, + 0x55, 0x52, 0x43, 0x45, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, + 0x53, 0x43, 0x4f, 0x50, 0x45, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x02, 0x12, 0x16, 0x0a, + 0x12, 0x55, 0x4e, 0x49, 0x56, 0x41, 0x52, 0x49, 0x41, 0x54, 0x45, 0x5f, 0x4d, 0x45, 0x54, 0x52, + 0x49, 0x43, 0x53, 0x10, 0x0a, 0x12, 0x16, 0x0a, 0x12, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x5f, + 0x44, 0x41, 0x54, 0x41, 0x5f, 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x53, 0x10, 0x0b, 0x12, 0x17, 0x0a, + 0x13, 0x53, 0x55, 0x4d, 0x4d, 0x41, 0x52, 0x59, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x50, 0x4f, + 0x49, 0x4e, 0x54, 0x53, 0x10, 0x0c, 0x12, 0x19, 0x0a, 0x15, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, + 0x52, 0x41, 0x4d, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x53, 0x10, + 0x0d, 0x12, 0x1d, 0x0a, 0x19, 0x45, 0x58, 0x50, 0x5f, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, + 0x41, 0x4d, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x53, 0x10, 0x0e, + 0x12, 0x13, 0x0a, 0x0f, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x5f, 0x44, 0x50, 0x5f, 0x41, 0x54, + 0x54, 0x52, 0x53, 0x10, 0x0f, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x55, 0x4d, 0x4d, 0x41, 0x52, 0x59, + 0x5f, 0x44, 0x50, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x10, 0x12, 0x16, 0x0a, 0x12, 0x48, + 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x5f, 0x44, 0x50, 0x5f, 0x41, 0x54, 0x54, 0x52, + 0x53, 0x10, 0x11, 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x58, 0x50, 0x5f, 0x48, 0x49, 0x53, 0x54, 0x4f, + 0x47, 0x52, 0x41, 0x4d, 0x5f, 0x44, 0x50, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x12, 0x12, + 0x17, 0x0a, 0x13, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x5f, 0x44, 0x50, 0x5f, 0x45, 0x58, 0x45, + 0x4d, 0x50, 0x4c, 0x41, 0x52, 0x53, 0x10, 0x13, 0x12, 0x1a, 0x0a, 0x16, 0x48, 0x49, 0x53, 0x54, + 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x5f, 0x44, 0x50, 0x5f, 0x45, 0x58, 0x45, 0x4d, 0x50, 0x4c, 0x41, + 0x52, 0x53, 0x10, 0x14, 0x12, 0x1e, 0x0a, 0x1a, 0x45, 0x58, 0x50, 0x5f, 0x48, 0x49, 0x53, 0x54, + 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x5f, 0x44, 0x50, 0x5f, 0x45, 0x58, 0x45, 0x4d, 0x50, 0x4c, 0x41, + 0x52, 0x53, 0x10, 0x15, 0x12, 0x1c, 0x0a, 0x18, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x5f, 0x44, + 0x50, 0x5f, 0x45, 0x58, 0x45, 0x4d, 0x50, 0x4c, 0x41, 0x52, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, + 0x10, 0x16, 0x12, 0x1f, 0x0a, 0x1b, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x5f, + 0x44, 0x50, 0x5f, 0x45, 0x58, 0x45, 0x4d, 0x50, 0x4c, 0x41, 0x52, 0x5f, 0x41, 0x54, 0x54, 0x52, + 0x53, 0x10, 0x17, 0x12, 0x23, 0x0a, 0x1f, 0x45, 0x58, 0x50, 0x5f, 0x48, 0x49, 0x53, 0x54, 0x4f, + 0x47, 0x52, 0x41, 0x4d, 0x5f, 0x44, 0x50, 0x5f, 0x45, 0x58, 0x45, 0x4d, 0x50, 0x4c, 0x41, 0x52, + 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x18, 0x12, 0x18, 0x0a, 0x14, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x56, 0x41, 0x52, 0x49, 0x41, 0x54, 0x45, 0x5f, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, - 0x10, 0x0a, 0x12, 0x16, 0x0a, 0x12, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x5f, 0x44, 0x41, 0x54, - 0x41, 0x5f, 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x53, 0x10, 0x0b, 0x12, 0x17, 0x0a, 0x13, 0x53, 0x55, - 0x4d, 0x4d, 0x41, 0x52, 0x59, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x50, 0x4f, 0x49, 0x4e, 0x54, - 0x53, 0x10, 0x0c, 0x12, 0x19, 0x0a, 0x15, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, 0x4d, - 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x53, 0x10, 0x0d, 0x12, 0x1d, - 0x0a, 0x19, 0x45, 0x58, 0x50, 0x5f, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x5f, - 0x44, 0x41, 0x54, 0x41, 0x5f, 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x53, 0x10, 0x0e, 0x12, 0x13, 0x0a, - 0x0f, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x5f, 0x44, 0x50, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, - 0x10, 0x0f, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x55, 0x4d, 0x4d, 0x41, 0x52, 0x59, 0x5f, 0x44, 0x50, - 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x10, 0x12, 0x16, 0x0a, 0x12, 0x48, 0x49, 0x53, 0x54, - 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x5f, 0x44, 0x50, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x11, - 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x58, 0x50, 0x5f, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, - 0x4d, 0x5f, 0x44, 0x50, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x12, 0x12, 0x17, 0x0a, 0x13, - 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x5f, 0x44, 0x50, 0x5f, 0x45, 0x58, 0x45, 0x4d, 0x50, 0x4c, - 0x41, 0x52, 0x53, 0x10, 0x13, 0x12, 0x1a, 0x0a, 0x16, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, - 0x41, 0x4d, 0x5f, 0x44, 0x50, 0x5f, 0x45, 0x58, 0x45, 0x4d, 0x50, 0x4c, 0x41, 0x52, 0x53, 0x10, - 0x14, 0x12, 0x1e, 0x0a, 0x1a, 0x45, 0x58, 0x50, 0x5f, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, - 0x41, 0x4d, 0x5f, 0x44, 0x50, 0x5f, 0x45, 0x58, 0x45, 0x4d, 0x50, 0x4c, 0x41, 0x52, 0x53, 0x10, - 0x15, 0x12, 0x1c, 0x0a, 0x18, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x5f, 0x44, 0x50, 0x5f, 0x45, - 0x58, 0x45, 0x4d, 0x50, 0x4c, 0x41, 0x52, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x16, 0x12, - 0x1f, 0x0a, 0x1b, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x5f, 0x44, 0x50, 0x5f, - 0x45, 0x58, 0x45, 0x4d, 0x50, 0x4c, 0x41, 0x52, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x17, - 0x12, 0x23, 0x0a, 0x1f, 0x45, 0x58, 0x50, 0x5f, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, - 0x4d, 0x5f, 0x44, 0x50, 0x5f, 0x45, 0x58, 0x45, 0x4d, 0x50, 0x4c, 0x41, 0x52, 0x5f, 0x41, 0x54, - 0x54, 0x52, 0x53, 0x10, 0x18, 0x12, 0x18, 0x0a, 0x14, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x56, 0x41, - 0x52, 0x49, 0x41, 0x54, 0x45, 0x5f, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x10, 0x19, 0x12, - 0x08, 0x0a, 0x04, 0x4c, 0x4f, 0x47, 0x53, 0x10, 0x1e, 0x12, 0x0d, 0x0a, 0x09, 0x4c, 0x4f, 0x47, - 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x1f, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x50, 0x41, 0x4e, - 0x53, 0x10, 0x28, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x50, 0x41, 0x4e, 0x5f, 0x41, 0x54, 0x54, 0x52, - 0x53, 0x10, 0x29, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x50, 0x41, 0x4e, 0x5f, 0x45, 0x56, 0x45, 0x4e, - 0x54, 0x53, 0x10, 0x2a, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x50, 0x41, 0x4e, 0x5f, 0x4c, 0x49, 0x4e, - 0x4b, 0x53, 0x10, 0x2b, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x50, 0x41, 0x4e, 0x5f, 0x45, 0x56, 0x45, - 0x4e, 0x54, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x2c, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x50, - 0x41, 0x4e, 0x5f, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x2d, 0x2a, - 0x61, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x06, 0x0a, - 0x02, 0x4f, 0x4b, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x45, - 0x44, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x41, 0x56, 0x41, 0x49, 0x4c, 0x41, 0x42, - 0x4c, 0x45, 0x10, 0x0e, 0x12, 0x14, 0x0a, 0x10, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, - 0x41, 0x52, 0x47, 0x55, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x03, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x45, - 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x45, 0x58, 0x48, 0x41, 0x55, 0x53, 0x54, 0x45, 0x44, - 0x10, 0x08, 0x32, 0xa0, 0x01, 0x0a, 0x12, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x54, 0x72, 0x61, 0x63, - 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x89, 0x01, 0x0a, 0x0b, 0x41, 0x72, - 0x72, 0x6f, 0x77, 0x54, 0x72, 0x61, 0x63, 0x65, 0x73, 0x12, 0x3c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, - 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2e, 0x61, 0x72, 0x72, - 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x41, 0x72, 0x72, 0x6f, 0x77, - 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x1a, 0x36, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, - 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, - 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2e, 0x61, 0x72, 0x72, 0x6f, 0x77, - 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, - 0x00, 0x28, 0x01, 0x30, 0x01, 0x32, 0x9c, 0x01, 0x0a, 0x10, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x4c, - 0x6f, 0x67, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x87, 0x01, 0x0a, 0x09, 0x41, - 0x72, 0x72, 0x6f, 0x77, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x3c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, - 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, - 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2e, 0x61, 0x72, 0x72, 0x6f, - 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x52, - 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x1a, 0x36, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, - 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x70, - 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2e, - 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, - 0x28, 0x01, 0x30, 0x01, 0x32, 0xa2, 0x01, 0x0a, 0x13, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x4d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x8a, 0x01, 0x0a, - 0x0c, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x3c, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, - 0x2e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x41, - 0x72, 0x72, 0x6f, 0x77, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x1a, 0x36, 0x2e, 0x6f, 0x70, + 0x10, 0x19, 0x12, 0x08, 0x0a, 0x04, 0x4c, 0x4f, 0x47, 0x53, 0x10, 0x1e, 0x12, 0x0d, 0x0a, 0x09, + 0x4c, 0x4f, 0x47, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x1f, 0x12, 0x09, 0x0a, 0x05, 0x53, + 0x50, 0x41, 0x4e, 0x53, 0x10, 0x28, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x50, 0x41, 0x4e, 0x5f, 0x41, + 0x54, 0x54, 0x52, 0x53, 0x10, 0x29, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x50, 0x41, 0x4e, 0x5f, 0x45, + 0x56, 0x45, 0x4e, 0x54, 0x53, 0x10, 0x2a, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x50, 0x41, 0x4e, 0x5f, + 0x4c, 0x49, 0x4e, 0x4b, 0x53, 0x10, 0x2b, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x50, 0x41, 0x4e, 0x5f, + 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, 0x10, 0x2c, 0x12, 0x13, 0x0a, + 0x0f, 0x53, 0x50, 0x41, 0x4e, 0x5f, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x53, + 0x10, 0x2d, 0x2a, 0x61, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, + 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x4b, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x41, 0x4e, 0x43, + 0x45, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x41, 0x56, 0x41, 0x49, + 0x4c, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x0e, 0x12, 0x14, 0x0a, 0x10, 0x49, 0x4e, 0x56, 0x41, 0x4c, + 0x49, 0x44, 0x5f, 0x41, 0x52, 0x47, 0x55, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x03, 0x12, 0x16, 0x0a, + 0x12, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x45, 0x58, 0x48, 0x41, 0x55, 0x53, + 0x54, 0x45, 0x44, 0x10, 0x08, 0x32, 0xa0, 0x01, 0x0a, 0x12, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x54, + 0x72, 0x61, 0x63, 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x89, 0x01, 0x0a, + 0x0b, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x54, 0x72, 0x61, 0x63, 0x65, 0x73, 0x12, 0x3c, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2e, + 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x41, 0x72, + 0x72, 0x6f, 0x77, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x1a, 0x36, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2e, 0x61, 0x72, + 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x32, 0x9c, 0x01, 0x0a, 0x10, 0x41, 0x72, 0x72, + 0x6f, 0x77, 0x4c, 0x6f, 0x67, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x87, 0x01, + 0x0a, 0x09, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x3c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2e, 0x61, - 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x83, 0x01, 0x0a, 0x2c, 0x69, 0x6f, + 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x41, 0x72, 0x72, + 0x6f, 0x77, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x1a, 0x36, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2e, 0x61, 0x72, 0x72, + 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x32, 0xa2, 0x01, 0x0a, 0x13, 0x41, 0x72, 0x72, 0x6f, + 0x77, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, + 0x8a, 0x01, 0x0a, 0x0c, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, + 0x12, 0x3c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, + 0x74, 0x61, 0x6c, 0x2e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, + 0x63, 0x68, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x1a, 0x36, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, - 0x6c, 0x2e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x42, 0x11, 0x41, 0x72, 0x72, 0x6f, - 0x77, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, - 0x3e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, - 0x2d, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2f, 0x6f, 0x74, 0x65, 0x6c, 0x2d, - 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, - 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2f, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2f, 0x76, 0x31, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6c, 0x2e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x83, 0x01, 0x0a, + 0x2c, 0x69, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, + 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, + 0x6e, 0x74, 0x61, 0x6c, 0x2e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2e, 0x76, 0x31, 0x42, 0x11, 0x41, + 0x72, 0x72, 0x6f, 0x77, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x50, 0x01, 0x5a, 0x3e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, + 0x70, 0x65, 0x6e, 0x2d, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2f, 0x6f, 0x74, + 0x65, 0x6c, 0x2d, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x65, 0x78, 0x70, + 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2f, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2f, + 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto/opentelemetry/proto/experimental/arrow/v1/arrow_service.proto b/proto/opentelemetry/proto/experimental/arrow/v1/arrow_service.proto index ba558c09..145a3e63 100644 --- a/proto/opentelemetry/proto/experimental/arrow/v1/arrow_service.proto +++ b/proto/opentelemetry/proto/experimental/arrow/v1/arrow_service.proto @@ -72,9 +72,6 @@ message BatchArrowRecords { // [optional] Headers associated with this batch, encoded using hpack. bytes headers = 3; - - // [mandatory] The uncompressed size of the batch. - uint64 uncompressed_size = 4; } // Enumeration of all the OTel Arrow payload types currently supported by the From 6f8ba19f5cdf7434403d7ec2e869bf9cb07196f1 Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Wed, 1 May 2024 15:21:17 -0400 Subject: [PATCH 17/28] add header, acquire diff --- .../internal/arrow/exporter.go | 6 ++ .../internal/arrow/exporter_test.go | 10 ++- .../internal/arrow/stream.go | 3 - collector/go.mod | 1 + collector/go.sum | 2 + .../receiver/otelarrowreceiver/config_test.go | 2 + .../receiver/otelarrowreceiver/factory.go | 3 +- .../otelarrowreceiver/internal/arrow/arrow.go | 84 ++++++++++++++----- .../otelarrowreceiver/testdata/config.yaml | 1 + 9 files changed, 83 insertions(+), 29 deletions(-) diff --git a/collector/exporter/otelarrowexporter/internal/arrow/exporter.go b/collector/exporter/otelarrowexporter/internal/arrow/exporter.go index aba9582e..eb384bb2 100644 --- a/collector/exporter/otelarrowexporter/internal/arrow/exporter.go +++ b/collector/exporter/otelarrowexporter/internal/arrow/exporter.go @@ -7,6 +7,7 @@ import ( "context" "errors" "math/rand" + "strconv" "sync" "time" @@ -296,6 +297,11 @@ func (e *Exporter) SendAndWait(ctx context.Context, data any) (bool, error) { uncompSize = sizer.MetricsSize(data) } + if md == nil { + md = make(map[string]string) + } + md["otlp-pdata-size"] = strconv.Itoa(uncompSize) + wri := writeItem{ records: data, md: md, diff --git a/collector/exporter/otelarrowexporter/internal/arrow/exporter_test.go b/collector/exporter/otelarrowexporter/internal/arrow/exporter_test.go index 2a0feaff..acca740a 100644 --- a/collector/exporter/otelarrowexporter/internal/arrow/exporter_test.go +++ b/collector/exporter/otelarrowexporter/internal/arrow/exporter_test.go @@ -604,10 +604,13 @@ func TestArrowExporterHeaders(t *testing.T) { md := metadata.MD{ "expected1": []string{"metadata1"}, "expected2": []string{fmt.Sprint(times)}, + "otlp-pdata-size": []string{"329"}, } expectOutput = append(expectOutput, md) } else { - expectOutput = append(expectOutput, nil) + expectOutput = append(expectOutput, metadata.MD{ + "otlp-pdata-size": []string{"329"}, + }) } sent, err := tc.exporter.SendAndWait(ctx, input) @@ -678,10 +681,13 @@ func TestArrowExporterIsTraced(t *testing.T) { md := metadata.MD{ "traceparent": []string{expectMap["traceparent"]}, + "otlp-pdata-size": []string{"329"}, } expectOutput = append(expectOutput, md) } else { - expectOutput = append(expectOutput, nil) + expectOutput = append(expectOutput, metadata.MD{ + "otlp-pdata-size": []string{"329"}, + }) } sent, err := tc.exporter.SendAndWait(ctx, input) diff --git a/collector/exporter/otelarrowexporter/internal/arrow/stream.go b/collector/exporter/otelarrowexporter/internal/arrow/stream.go index dba62410..3a55105b 100644 --- a/collector/exporter/otelarrowexporter/internal/arrow/stream.go +++ b/collector/exporter/otelarrowexporter/internal/arrow/stream.go @@ -318,9 +318,6 @@ func (s *Stream) encodeAndSend(wri writeItem, hdrsBuf *bytes.Buffer, hdrsEnc *hp wri.errCh <- consumererror.NewPermanent(err) return err } - fmt.Println("EXPORTER SIDE UNCOMP SIZE") - fmt.Println(wri.uncompSize) - batch.UncompressedSize = uint64(wri.uncompSize) // Optionally include outgoing metadata, if present. if len(wri.md) != 0 { diff --git a/collector/go.mod b/collector/go.mod index 3e54d0a8..44cf226a 100644 --- a/collector/go.mod +++ b/collector/go.mod @@ -32,6 +32,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/knadh/koanf/maps v0.1.1 // indirect github.com/knadh/koanf/providers/confmap v0.1.0 // indirect diff --git a/collector/go.sum b/collector/go.sum index 982108ba..5294b86a 100644 --- a/collector/go.sum +++ b/collector/go.sum @@ -18,6 +18,8 @@ github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 h1:TQcrn6Wq+sKGkpyPvppOz99zsM github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= diff --git a/collector/receiver/otelarrowreceiver/config_test.go b/collector/receiver/otelarrowreceiver/config_test.go index 315f2968..659b11c8 100644 --- a/collector/receiver/otelarrowreceiver/config_test.go +++ b/collector/receiver/otelarrowreceiver/config_test.go @@ -78,6 +78,7 @@ func TestUnmarshalConfig(t *testing.T) { }, Arrow: ArrowConfig{ MemoryLimitMiB: 123, + AdmissionLimitMiB: 80, }, }, }, cfg) @@ -102,6 +103,7 @@ func TestUnmarshalConfigUnix(t *testing.T) { }, Arrow: ArrowConfig{ MemoryLimitMiB: defaultMemoryLimitMiB, + AdmissionLimitMiB: defaultAdmissionLimitMiB, }, }, }, cfg) diff --git a/collector/receiver/otelarrowreceiver/factory.go b/collector/receiver/otelarrowreceiver/factory.go index e2a8cd78..7269084f 100644 --- a/collector/receiver/otelarrowreceiver/factory.go +++ b/collector/receiver/otelarrowreceiver/factory.go @@ -20,6 +20,7 @@ const ( defaultGRPCEndpoint = "0.0.0.0:4317" defaultMemoryLimitMiB = 128 + defaultAdmissionLimitMiB = defaultMemoryLimitMiB / 2 ) // NewFactory creates a new OTLP receiver factory. @@ -46,7 +47,7 @@ func createDefaultConfig() component.Config { }, Arrow: ArrowConfig{ MemoryLimitMiB: defaultMemoryLimitMiB, - // AdmissionLimitMiB: defaultMemoryLimitMiB/2, + AdmissionLimitMiB: defaultAdmissionLimitMiB, }, }, } diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go index db93af38..01f2c4d4 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go @@ -9,9 +9,11 @@ import ( "fmt" "io" "runtime" + "strconv" "strings" "sync" + "github.com/golang/protobuf/proto" arrowpb "github.com/open-telemetry/otel-arrow/api/experimental/arrow/v1" "github.com/open-telemetry/otel-arrow/collector/netstats" arrowRecord "github.com/open-telemetry/otel-arrow/pkg/otel/arrow_record" @@ -403,6 +405,7 @@ func (r *Receiver) recvOne(ctx context.Context, serverStream anyStreamServer, hr } }() + // Receive a batch corresponding with one ptrace.Traces, pmetric.Metrics, // or plog.Logs item. req, err := serverStream.Recv() @@ -416,21 +419,30 @@ func (r *Receiver) recvOne(ctx context.Context, serverStream anyStreamServer, hr return err } - uncompSz := int64(req.GetUncompressedSize()) - // bounded queue to memory limit based on incoming uncompressed request size and waiters. - // Acquire will fail immediately if there are too many waiters, - // or will otherwise block until timeout or enough memory becomes available. - err = r.boundedQueue.Acquire(ctx, uncompSz) - if err != nil { - return fmt.Errorf("breaking stream: %v", err) - } - // Check for optional headers and set the incoming context. thisCtx, authHdrs, err := hrcv.combineHeaders(ctx, req.GetHeaders()) if err != nil { // Failing to parse the incoming headers breaks the stream. return fmt.Errorf("arrow metadata error: %v", err) } + var sizeBytes int + uncompSizeStr, ok := authHdrs["otlp-pdata-size"] + if !ok || len(uncompSizeStr) == 0 { + // This is a compressed size so make sure to acquire the difference when request is decompressed. + sizeBytes = proto.Size(req) + } else { + sizeBytes, err = strconv.Atoi(uncompSizeStr[0]) + if err != nil { + return fmt.Errorf("failed to convert string to request size: %v", err) + } + } + // bounded queue to memory limit based on incoming uncompressed request size and waiters. + // Acquire will fail immediately if there are too many waiters, + // or will otherwise block until timeout or enough memory becomes available. + err = r.boundedQueue.Acquire(ctx, int64(sizeBytes)) + if err != nil { + return fmt.Errorf("breaking stream: %v", err) + } var authErr error if r.authServer != nil { @@ -445,7 +457,7 @@ func (r *Receiver) recvOne(ctx context.Context, serverStream anyStreamServer, hr // processAndConsume will process and send an error to the sender loop go func() { defer r.inFlightWG.Done() // done processing - r.processAndConsume(thisCtx, method, ac, req, serverStream, authErr, pendingCh) + r.processAndConsume(thisCtx, method, ac, req, serverStream, authErr, pendingCh, int64(sizeBytes)) }() return nil @@ -469,7 +481,6 @@ func (r *Receiver) srvReceiveLoop(ctx context.Context, serverStream anyStreamSer func (r *Receiver) sendOne(serverStream anyStreamServer, resp batchResp) error { // Note: Statuses can be batched, but we do not take // advantage of this feature. - status := &arrowpb.BatchStatus{ BatchId: resp.id, } @@ -535,7 +546,7 @@ func (r *Receiver) srvSendLoop(ctx context.Context, serverStream anyStreamServer } } -func (r *Receiver) processAndConsume(ctx context.Context, method string, arrowConsumer arrowRecord.ConsumerAPI, req *arrowpb.BatchArrowRecords, serverStream anyStreamServer, authErr error, pendingCh chan<- batchResp) { +func (r *Receiver) processAndConsume(ctx context.Context, method string, arrowConsumer arrowRecord.ConsumerAPI, req *arrowpb.BatchArrowRecords, serverStream anyStreamServer, authErr error, pendingCh chan<- batchResp, sizeBytes int64) { var err error ctx, span := r.tracer.Start(ctx, "otel_arrow_stream_recv") @@ -553,15 +564,17 @@ func (r *Receiver) processAndConsume(ctx context.Context, method string, arrowCo // Process records: an error in this code path does // not necessarily break the stream. + toRelease := sizeBytes if authErr != nil { err = authErr } else { - err = r.processRecords(ctx, method, arrowConsumer, req) + toRelease, err = r.processRecords(ctx, method, arrowConsumer, req, sizeBytes) } + pendingCh <- batchResp{ id: req.GetBatchId(), err: err, - uncompSz: int64(req.GetUncompressedSize()), + uncompSz: toRelease, } } @@ -569,10 +582,10 @@ func (r *Receiver) processAndConsume(ctx context.Context, method string, arrowCo // the error (true) was from processing the data (i.e., invalid // argument) or (false) from the consuming pipeline. The boolean is // not used when success (nil error) is returned. -func (r *Receiver) processRecords(ctx context.Context, method string, arrowConsumer arrowRecord.ConsumerAPI, records *arrowpb.BatchArrowRecords) error { +func (r *Receiver) processRecords(ctx context.Context, method string, arrowConsumer arrowRecord.ConsumerAPI, records *arrowpb.BatchArrowRecords, sizeBytes int64) (int64, error) { payloads := records.GetArrowPayloads() if len(payloads) == 0 { - return nil + return sizeBytes, nil } var uncompSize int64 if r.telemetry.MetricsLevel > configtelemetry.LevelNormal { @@ -594,7 +607,7 @@ func (r *Receiver) processRecords(ctx context.Context, method string, arrowConsu switch payloads[0].Type { case arrowpb.ArrowPayloadType_UNIVARIATE_METRICS: if r.Metrics() == nil { - return status.Error(codes.Unimplemented, "metrics service not available") + return sizeBytes, status.Error(codes.Unimplemented, "metrics service not available") } var sizer pmetric.ProtoMarshaler var numPts int @@ -618,16 +631,24 @@ func (r *Receiver) processRecords(ctx context.Context, method string, arrowConsu r.Metrics().ConsumeMetrics(ctx, metrics), ) } + // already acquired sizeBytes, but if this was compressed size we need to acquire the difference. + diff := uncompSize - sizeBytes + acquireErr := r.boundedQueue.Acquire(ctx, int64(diff)) + if acquireErr != nil { + err = multierr.Append(err, acquireErr) + // failed to acquire so can't just return the uncompSize in case sizeBytes is a compressed size. + return sizeBytes, err + } // entire request has been processed, decrement counter. r.recvInFlightBytes.Add(ctx, -uncompSize) r.recvInFlightItems.Add(ctx, int64(-numPts)) } r.obsrecv.EndMetricsOp(ctx, streamFormat, numPts, err) - return err + return uncompSize, err case arrowpb.ArrowPayloadType_LOGS: if r.Logs() == nil { - return status.Error(codes.Unimplemented, "logs service not available") + return sizeBytes, status.Error(codes.Unimplemented, "logs service not available") } var sizer plog.ProtoMarshaler var numLogs int @@ -649,16 +670,25 @@ func (r *Receiver) processRecords(ctx context.Context, method string, arrowConsu r.Logs().ConsumeLogs(ctx, logs), ) } + // already acquired sizeBytes, but if this was compressed size we need to acquire the difference. + diff := uncompSize - sizeBytes + acquireErr := r.boundedQueue.Acquire(ctx, int64(diff)) + if acquireErr != nil { + err = multierr.Append(err, acquireErr) + // failed to acquire so can't just return the uncompSize in case sizeBytes is a compressed size. + return sizeBytes, err + } + // entire request has been processed, decrement counter. r.recvInFlightBytes.Add(ctx, -uncompSize) r.recvInFlightItems.Add(ctx, int64(-numLogs)) } r.obsrecv.EndLogsOp(ctx, streamFormat, numLogs, err) - return err + return uncompSize, err case arrowpb.ArrowPayloadType_SPANS: if r.Traces() == nil { - return status.Error(codes.Unimplemented, "traces service not available") + return sizeBytes, status.Error(codes.Unimplemented, "traces service not available") } var sizer ptrace.ProtoMarshaler var numSpans int @@ -681,15 +711,23 @@ func (r *Receiver) processRecords(ctx context.Context, method string, arrowConsu r.Traces().ConsumeTraces(ctx, traces), ) } + // already acquired sizeBytes, but if this was compressed size we need to acquire the difference. + diff := uncompSize - sizeBytes + acquireErr := r.boundedQueue.Acquire(ctx, int64(diff)) + if acquireErr != nil { + err = multierr.Append(err, acquireErr) + // failed to acquire so can't just return the uncompSize in case sizeBytes is a compressed size. + return sizeBytes, err + } // entire request has been processed, decrement counter. r.recvInFlightBytes.Add(ctx, -uncompSize) r.recvInFlightItems.Add(ctx, int64(-numSpans)) } r.obsrecv.EndTracesOp(ctx, streamFormat, numSpans, err) - return err + return uncompSize, err default: - return ErrUnrecognizedPayload + return sizeBytes, ErrUnrecognizedPayload } } diff --git a/collector/receiver/otelarrowreceiver/testdata/config.yaml b/collector/receiver/otelarrowreceiver/testdata/config.yaml index 0db44373..77a849af 100644 --- a/collector/receiver/otelarrowreceiver/testdata/config.yaml +++ b/collector/receiver/otelarrowreceiver/testdata/config.yaml @@ -27,3 +27,4 @@ protocols: permit_without_stream: true arrow: memory_limit_mib: 123 + admission_limit_mib: 80 From af29366adc454233a2244638be992cc2feabd0f2 Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Thu, 2 May 2024 15:41:22 -0400 Subject: [PATCH 18/28] fix potential deadlock --- .../otelarrowreceiver/internal/arrow/arrow.go | 86 ++++++++++++------- 1 file changed, 55 insertions(+), 31 deletions(-) diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go index 01f2c4d4..8302fb15 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go @@ -425,13 +425,13 @@ func (r *Receiver) recvOne(ctx context.Context, serverStream anyStreamServer, hr // Failing to parse the incoming headers breaks the stream. return fmt.Errorf("arrow metadata error: %v", err) } - var sizeBytes int - uncompSizeStr, ok := authHdrs["otlp-pdata-size"] - if !ok || len(uncompSizeStr) == 0 { + var prevAcquiredBytes int + uncompSizeStr, sizeHeaderFound := authHdrs["otlp-pdata-size"] + if !sizeHeaderFound || len(uncompSizeStr) == 0 { // This is a compressed size so make sure to acquire the difference when request is decompressed. - sizeBytes = proto.Size(req) + prevAcquiredBytes = proto.Size(req) } else { - sizeBytes, err = strconv.Atoi(uncompSizeStr[0]) + prevAcquiredBytes, err = strconv.Atoi(uncompSizeStr[0]) if err != nil { return fmt.Errorf("failed to convert string to request size: %v", err) } @@ -439,7 +439,7 @@ func (r *Receiver) recvOne(ctx context.Context, serverStream anyStreamServer, hr // bounded queue to memory limit based on incoming uncompressed request size and waiters. // Acquire will fail immediately if there are too many waiters, // or will otherwise block until timeout or enough memory becomes available. - err = r.boundedQueue.Acquire(ctx, int64(sizeBytes)) + err = r.boundedQueue.Acquire(ctx, int64(prevAcquiredBytes)) if err != nil { return fmt.Errorf("breaking stream: %v", err) } @@ -457,7 +457,7 @@ func (r *Receiver) recvOne(ctx context.Context, serverStream anyStreamServer, hr // processAndConsume will process and send an error to the sender loop go func() { defer r.inFlightWG.Done() // done processing - r.processAndConsume(thisCtx, method, ac, req, serverStream, authErr, pendingCh, int64(sizeBytes)) + r.processAndConsume(thisCtx, method, ac, req, serverStream, authErr, pendingCh, int64(prevAcquiredBytes), sizeHeaderFound) }() return nil @@ -546,7 +546,7 @@ func (r *Receiver) srvSendLoop(ctx context.Context, serverStream anyStreamServer } } -func (r *Receiver) processAndConsume(ctx context.Context, method string, arrowConsumer arrowRecord.ConsumerAPI, req *arrowpb.BatchArrowRecords, serverStream anyStreamServer, authErr error, pendingCh chan<- batchResp, sizeBytes int64) { +func (r *Receiver) processAndConsume(ctx context.Context, method string, arrowConsumer arrowRecord.ConsumerAPI, req *arrowpb.BatchArrowRecords, serverStream anyStreamServer, authErr error, pendingCh chan<- batchResp, prevAcquiredBytes int64, sizeHeaderFound bool) { var err error ctx, span := r.tracer.Start(ctx, "otel_arrow_stream_recv") @@ -564,11 +564,11 @@ func (r *Receiver) processAndConsume(ctx context.Context, method string, arrowCo // Process records: an error in this code path does // not necessarily break the stream. - toRelease := sizeBytes + toRelease := prevAcquiredBytes if authErr != nil { err = authErr } else { - toRelease, err = r.processRecords(ctx, method, arrowConsumer, req, sizeBytes) + toRelease, err = r.processRecords(ctx, method, arrowConsumer, req, prevAcquiredBytes, sizeHeaderFound) } pendingCh <- batchResp{ @@ -582,10 +582,10 @@ func (r *Receiver) processAndConsume(ctx context.Context, method string, arrowCo // the error (true) was from processing the data (i.e., invalid // argument) or (false) from the consuming pipeline. The boolean is // not used when success (nil error) is returned. -func (r *Receiver) processRecords(ctx context.Context, method string, arrowConsumer arrowRecord.ConsumerAPI, records *arrowpb.BatchArrowRecords, sizeBytes int64) (int64, error) { +func (r *Receiver) processRecords(ctx context.Context, method string, arrowConsumer arrowRecord.ConsumerAPI, records *arrowpb.BatchArrowRecords, prevAcquiredBytes int64, sizeHeaderFound bool) (int64, error) { payloads := records.GetArrowPayloads() if len(payloads) == 0 { - return sizeBytes, nil + return prevAcquiredBytes, nil } var uncompSize int64 if r.telemetry.MetricsLevel > configtelemetry.LevelNormal { @@ -607,7 +607,7 @@ func (r *Receiver) processRecords(ctx context.Context, method string, arrowConsu switch payloads[0].Type { case arrowpb.ArrowPayloadType_UNIVARIATE_METRICS: if r.Metrics() == nil { - return sizeBytes, status.Error(codes.Unimplemented, "metrics service not available") + return prevAcquiredBytes, status.Error(codes.Unimplemented, "metrics service not available") } var sizer pmetric.ProtoMarshaler var numPts int @@ -631,14 +631,15 @@ func (r *Receiver) processRecords(ctx context.Context, method string, arrowConsu r.Metrics().ConsumeMetrics(ctx, metrics), ) } - // already acquired sizeBytes, but if this was compressed size we need to acquire the difference. - diff := uncompSize - sizeBytes - acquireErr := r.boundedQueue.Acquire(ctx, int64(diff)) + + acquireErr := r.acquireAdditionalBytes(ctx, uncompSize, prevAcquiredBytes, sizeHeaderFound) + if acquireErr != nil { err = multierr.Append(err, acquireErr) - // failed to acquire so can't just return the uncompSize in case sizeBytes is a compressed size. - return sizeBytes, err + // if acquireAdditionalBytes() failed then the previously acquired bytes were already released i.e. nothing to releaes. + return 0, err } + // entire request has been processed, decrement counter. r.recvInFlightBytes.Add(ctx, -uncompSize) r.recvInFlightItems.Add(ctx, int64(-numPts)) @@ -648,7 +649,7 @@ func (r *Receiver) processRecords(ctx context.Context, method string, arrowConsu case arrowpb.ArrowPayloadType_LOGS: if r.Logs() == nil { - return sizeBytes, status.Error(codes.Unimplemented, "logs service not available") + return prevAcquiredBytes, status.Error(codes.Unimplemented, "logs service not available") } var sizer plog.ProtoMarshaler var numLogs int @@ -670,13 +671,13 @@ func (r *Receiver) processRecords(ctx context.Context, method string, arrowConsu r.Logs().ConsumeLogs(ctx, logs), ) } - // already acquired sizeBytes, but if this was compressed size we need to acquire the difference. - diff := uncompSize - sizeBytes - acquireErr := r.boundedQueue.Acquire(ctx, int64(diff)) + + acquireErr := r.acquireAdditionalBytes(ctx, uncompSize, prevAcquiredBytes, sizeHeaderFound) + if acquireErr != nil { err = multierr.Append(err, acquireErr) - // failed to acquire so can't just return the uncompSize in case sizeBytes is a compressed size. - return sizeBytes, err + // if acquireAdditionalBytes() failed then the previously acquired bytes were already released i.e. nothing to releaes. + return 0, err } // entire request has been processed, decrement counter. @@ -688,7 +689,7 @@ func (r *Receiver) processRecords(ctx context.Context, method string, arrowConsu case arrowpb.ArrowPayloadType_SPANS: if r.Traces() == nil { - return sizeBytes, status.Error(codes.Unimplemented, "traces service not available") + return prevAcquiredBytes, status.Error(codes.Unimplemented, "traces service not available") } var sizer ptrace.ProtoMarshaler var numSpans int @@ -711,13 +712,13 @@ func (r *Receiver) processRecords(ctx context.Context, method string, arrowConsu r.Traces().ConsumeTraces(ctx, traces), ) } - // already acquired sizeBytes, but if this was compressed size we need to acquire the difference. - diff := uncompSize - sizeBytes - acquireErr := r.boundedQueue.Acquire(ctx, int64(diff)) + + acquireErr := r.acquireAdditionalBytes(ctx, uncompSize, prevAcquiredBytes, sizeHeaderFound) + if acquireErr != nil { err = multierr.Append(err, acquireErr) - // failed to acquire so can't just return the uncompSize in case sizeBytes is a compressed size. - return sizeBytes, err + // if acquireAdditionalBytes() failed then the previously acquired bytes were already released i.e. nothing to releaes. + return 0, err } // entire request has been processed, decrement counter. @@ -728,6 +729,29 @@ func (r *Receiver) processRecords(ctx context.Context, method string, arrowConsu return uncompSize, err default: - return sizeBytes, ErrUnrecognizedPayload + return prevAcquiredBytes, ErrUnrecognizedPayload + } +} + +func (r *Receiver) acquireAdditionalBytes(ctx context.Context, uncompSize int64, prevAcquiredBytes int64, sizeHeaderFound bool) error { + diff := uncompSize - prevAcquiredBytes + + var err error + if diff != 0 { + if sizeHeaderFound { + // a mismatch between header set by exporter and the uncompSize just calculated. + r.telemetry.Logger.Debug("mismatch between uncompressed size in receiver and otlp-pdata-size header", zap.Int("uncompsize", int(uncompSize)), zap.Int("otlp-pdata-size", int(prevAcquiredBytes))) + } else if diff < 0 { + // proto.Size() on compressed request was greater than pdata uncompressed size. + r.telemetry.Logger.Debug("uncompressed size is less than compressed size", zap.Int("uncompressed", int(uncompSize)), zap.Int("compressed", int(prevAcquiredBytes))) + } + + // regardless of the reason, if diff is not 0 then Release previously acquired bytes + // to prevent deadlock and reacquire the uncompressed size we just calculated. + r.boundedQueue.Release(prevAcquiredBytes) + err = r.boundedQueue.Acquire(ctx, uncompSize) } + + return err } + From 3b09b6c75f93d47658ef0c7f08d0e0b3d0f5bf40 Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Fri, 3 May 2024 15:25:01 -0400 Subject: [PATCH 19/28] unit tests --- .../internal/arrow/arrow_test.go | 224 ++++++++++++++++-- 1 file changed, 210 insertions(+), 14 deletions(-) diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go index a2e66016..6729f920 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go @@ -9,6 +9,7 @@ import ( "encoding/json" "fmt" "io" + "strconv" "strings" "sync" "testing" @@ -47,6 +48,8 @@ import ( "github.com/open-telemetry/otel-arrow/collector/receiver/otelarrowreceiver/internal/arrow/mock" ) +var defaultBQ = admission.NewBoundedQueue(int64(100000), int64(10)) + type compareJSONTraces struct{ ptrace.Traces } type compareJSONMetrics struct{ pmetric.Metrics } type compareJSONLogs struct{ plog.Logs } @@ -321,7 +324,7 @@ func (ctc *commonTestCase) newOOMConsumer() arrowRecord.ConsumerAPI { return mock } -func (ctc *commonTestCase) start(newConsumer func() arrowRecord.ConsumerAPI, opts ...func(*configgrpc.ServerConfig, *auth.Server)) { +func (ctc *commonTestCase) start(newConsumer func() arrowRecord.ConsumerAPI, bq *admission.BoundedQueue, opts ...func(*configgrpc.ServerConfig, *auth.Server)) { var authServer auth.Server var gsettings configgrpc.ServerConfig for _, gf := range opts { @@ -345,7 +348,7 @@ func (ctc *commonTestCase) start(newConsumer func() arrowRecord.ConsumerAPI, opt gsettings, authServer, newConsumer, - admission.NewBoundedQueue(int64(10490000), int64(10)), + bq, netstats.Noop{}, ) require.NoError(ctc.T, err) @@ -361,6 +364,199 @@ func requireCanceledStatus(t *testing.T, err error) { require.Equal(t, codes.Canceled, status.Code()) } +func TestBoundedQueueWithPdataHeaders(t *testing.T) { + var sizer ptrace.ProtoMarshaler + pdataSizeTenTraces := sizer.TracesSize(testdata.GenerateTraces(10)) + defaultBoundedQueueLimit := int64(100000) + tests := []struct{ + name string + numTraces int + includePdataHeader bool + pdataSize string + rejected bool + }{ + { + name: "no header compressed greater than uncompressed", + numTraces: 10, + }, + { + name: "no header compressed less than uncompressed", + numTraces: 100, + }, + { + name: "pdata header less than uncompressedSize", + numTraces: 10, + pdataSize: strconv.Itoa(pdataSizeTenTraces / 2), + includePdataHeader: true, + }, + { + name: "pdata header equal uncompressedSize", + numTraces: 10, + pdataSize: strconv.Itoa(pdataSizeTenTraces), + includePdataHeader: true, + }, + { + name: "pdata header greater than uncompressedSize", + numTraces: 10, + pdataSize: strconv.Itoa(pdataSizeTenTraces * 2), + includePdataHeader: true, + }, + { + name: "no header compressed accepted uncompressed rejected", + numTraces: 100, + rejected: true, + }, + { + name: "pdata header accepted uncompressed rejected", + numTraces: 100, + rejected: true, + pdataSize: strconv.Itoa(pdataSizeTenTraces), + includePdataHeader: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tc := healthyTestChannel{} + ctc := newCommonTestCase(t, tc) + + td := testdata.GenerateTraces(tt.numTraces) + batch, err := ctc.testProducer.BatchArrowRecordsFromTraces(td) + require.NoError(t, err) + if tt.includePdataHeader { + var hpb bytes.Buffer + hpe := hpack.NewEncoder(&hpb) + err := hpe.WriteField(hpack.HeaderField{ + Name: "otlp-pdata-size", + Value: tt.pdataSize, + }) + assert.NoError(t, err) + batch.Headers = make([]byte, hpb.Len()) + copy(batch.Headers, hpb.Bytes()) + } + + var bq *admission.BoundedQueue + if tt.rejected { + ctc.stream.EXPECT().Send(statusUnavailableFor(batch.BatchId, "rejecting request, request size larger than configured limit")).Times(1).Return(fmt.Errorf("rejecting request, request size larger than configured limit")) + // make the boundedqueue limit be slightly less than the uncompressed size + bq = admission.NewBoundedQueue(int64(sizer.TracesSize(td) - 100), int64(10)) + } else { + ctc.stream.EXPECT().Send(statusOKFor(batch.BatchId)).Times(1).Return(nil) + bq = admission.NewBoundedQueue(defaultBoundedQueueLimit, int64(10)) + } + + ctc.start(ctc.newRealConsumer, bq) + ctc.putBatch(batch, nil) + + if tt.rejected { + ctc.cancel() + } + + select { + case data := <-ctc.consume: + actualTD := data.Data.(ptrace.Traces) + assertEqualUnsortedSpans(t, td, actualTD) + err = ctc.cancelAndWait() + requireCanceledStatus(t, err) + case err = <-ctc.streamErr: + requireCanceledStatus(t, err) + } + }) + } +} + +// order of spans might not be guaranteed, so sort the span objects by spanID and check equality. +func assertEqualUnsortedSpans(t *testing.T, a, b ptrace.Traces) { + assert.Equal(t, a.SpanCount(), b.SpanCount()) + + rssA := a.ResourceSpans() + rssB := b.ResourceSpans() + assert.Equal(t, rssA.Len(), rssB.Len()) + + rssA.Sort(sortResourceSpans) + rssB.Sort(sortResourceSpans) + for i := 0; i < rssA.Len(); i++ { + rsA := rssA.At(i) + rsB := rssB.At(i) + assert.Equal(t, rsA.Resource(), rsB.Resource()) + + sssA := rsA.ScopeSpans() + sssB := rsB.ScopeSpans() + assert.Equal(t, sssA.Len(), sssB.Len()) + + sssA.Sort(sortScopeSpans) + sssB.Sort(sortScopeSpans) + + for j := 0; j < sssA.Len(); j++ { + ssA := sssA.At(j) + ssB := sssB.At(j) + assert.Equal(t, ssA.Scope(), ssB.Scope()) + + spanSliceA := ssA.Spans() + spanSliceB := ssB.Spans() + assert.Equal(t, spanSliceA.Len(), spanSliceB.Len()) + + spanSliceA.Sort(sortSpans) + spanSliceB.Sort(sortSpans) + + assert.Equal(t, spanSliceA, spanSliceB) + } + } +} + +func sortResourceSpans(a, b ptrace.ResourceSpans) bool { + assl := a.ScopeSpans() + bssl := b.ScopeSpans() + + if assl.Len() == 0 { + return true + } + if bssl.Len() == 0 { + return false + } + + assl.Sort(sortScopeSpans) + bssl.Sort(sortScopeSpans) + + if assl.At(0).Spans().Len() == 0 { + return true + } + if bssl.At(0).Spans().Len() == 0 { + return false + } + + if assl.At(0).Spans().At(0).SpanID().String() < bssl.At(0).Spans().At(0).SpanID().String() { + return true + } + return false +} + +func sortScopeSpans(a, b ptrace.ScopeSpans) bool { + asl := a.Spans() + bsl := a.Spans() + + if asl.Len() == 0 { + return true + } + if bsl.Len() == 0 { + return false + } + + asl.Sort(sortSpans) + bsl.Sort(sortSpans) + + if asl.At(0).SpanID().String() < bsl.At(0).SpanID().String() { + return true + } + return false +} + +func sortSpans(a, b ptrace.Span) bool { + if a.SpanID().String() < b.SpanID().String() { + return true + } + return false +} + func TestReceiverTraces(t *testing.T) { tc := healthyTestChannel{} ctc := newCommonTestCase(t, tc) @@ -371,7 +567,7 @@ func TestReceiverTraces(t *testing.T) { ctc.stream.EXPECT().Send(statusOKFor(batch.BatchId)).Times(1).Return(nil) - ctc.start(ctc.newRealConsumer) + ctc.start(ctc.newRealConsumer, defaultBQ) ctc.putBatch(batch, nil) assert.EqualValues(t, td, (<-ctc.consume).Data) @@ -390,7 +586,7 @@ func TestReceiverLogs(t *testing.T) { ctc.stream.EXPECT().Send(statusOKFor(batch.BatchId)).Times(1).Return(nil) - ctc.start(ctc.newRealConsumer) + ctc.start(ctc.newRealConsumer, defaultBQ) ctc.putBatch(batch, nil) assert.EqualValues(t, []json.Marshaler{compareJSONLogs{ld}}, []json.Marshaler{compareJSONLogs{(<-ctc.consume).Data.(plog.Logs)}}) @@ -410,7 +606,7 @@ func TestReceiverMetrics(t *testing.T) { ctc.stream.EXPECT().Send(statusOKFor(batch.BatchId)).Times(1).Return(nil) - ctc.start(ctc.newRealConsumer) + ctc.start(ctc.newRealConsumer, defaultBQ) ctc.putBatch(batch, nil) otelAssert.Equiv(stdTesting, []json.Marshaler{ @@ -427,7 +623,7 @@ func TestReceiverRecvError(t *testing.T) { tc := healthyTestChannel{} ctc := newCommonTestCase(t, tc) - ctc.start(ctc.newRealConsumer) + ctc.start(ctc.newRealConsumer, defaultBQ) ctc.putBatch(nil, fmt.Errorf("test recv error")) @@ -446,7 +642,7 @@ func TestReceiverSendError(t *testing.T) { ctc.stream.EXPECT().Send(statusOKFor(batch.BatchId)).Times(1).Return(fmt.Errorf("test send error")) - ctc.start(ctc.newRealConsumer) + ctc.start(ctc.newRealConsumer, defaultBQ) ctc.putBatch(batch, nil) assert.EqualValues(t, ld, (<-ctc.consume).Data) @@ -487,7 +683,7 @@ func TestReceiverConsumeError(t *testing.T) { ctc.stream.EXPECT().Send(statusUnavailableFor(batch.BatchId, "consumer unhealthy")).Times(1).Return(nil) - ctc.start(ctc.newRealConsumer) + ctc.start(ctc.newRealConsumer, defaultBQ) ctc.putBatch(batch, nil) @@ -546,7 +742,7 @@ func TestReceiverInvalidData(t *testing.T) { ctc.stream.EXPECT().Send(statusInvalidFor(batch.BatchId, "Permanent error: test invalid error")).Times(1).Return(nil) - ctc.start(ctc.newErrorConsumer) + ctc.start(ctc.newErrorConsumer, defaultBQ) ctc.putBatch(batch, nil) err = ctc.cancelAndWait() @@ -583,7 +779,7 @@ func TestReceiverMemoryLimit(t *testing.T) { ctc.stream.EXPECT().Send(statusExhaustedFor(batch.BatchId, "Permanent error: test oom error "+arrowRecord.ErrConsumerMemoryLimit.Error())).Times(1).Return(nil) - ctc.start(ctc.newOOMConsumer) + ctc.start(ctc.newOOMConsumer, defaultBQ) ctc.putBatch(batch, nil) err = ctc.cancelAndWait() @@ -629,7 +825,7 @@ func TestReceiverEOF(t *testing.T) { ctc.stream.EXPECT().Send(gomock.Any()).Times(times).Return(nil) - ctc.start(ctc.newRealConsumer) + ctc.start(ctc.newRealConsumer, defaultBQ) go func() { for i := 0; i < times; i++ { @@ -686,7 +882,7 @@ func testReceiverHeaders(t *testing.T, includeMeta bool) { ctc.stream.EXPECT().Send(gomock.Any()).Times(len(expectData)).Return(nil) - ctc.start(ctc.newRealConsumer, func(gsettings *configgrpc.ServerConfig, _ *auth.Server) { + ctc.start(ctc.newRealConsumer, defaultBQ, func(gsettings *configgrpc.ServerConfig, _ *auth.Server) { gsettings.IncludeMetadata = includeMeta }) @@ -758,7 +954,7 @@ func TestReceiverCancel(t *testing.T) { ctc := newCommonTestCase(t, tc) ctc.cancel() - ctc.start(ctc.newRealConsumer) + ctc.start(ctc.newRealConsumer, defaultBQ) err := ctc.wait() requireCanceledStatus(t, err) @@ -1048,7 +1244,7 @@ func testReceiverAuthHeaders(t *testing.T, includeMeta bool, dataAuth bool) { }) var authCall *gomock.Call - ctc.start(ctc.newRealConsumer, func(gsettings *configgrpc.ServerConfig, authPtr *auth.Server) { + ctc.start(ctc.newRealConsumer, defaultBQ, func(gsettings *configgrpc.ServerConfig, authPtr *auth.Server) { gsettings.IncludeMetadata = includeMeta as := mock.NewMockServer(ctc.ctrl) From 1258605e3893c37721071597efb9c7107cae51ed Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Fri, 3 May 2024 15:33:27 -0400 Subject: [PATCH 20/28] use assertEqualUnsortedSpans --- .../otelarrowreceiver/internal/arrow/arrow_test.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go index 6729f920..3c45bb87 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go @@ -570,7 +570,7 @@ func TestReceiverTraces(t *testing.T) { ctc.start(ctc.newRealConsumer, defaultBQ) ctc.putBatch(batch, nil) - assert.EqualValues(t, td, (<-ctc.consume).Data) + assertEqualUnsortedSpans(t, td, (<-ctc.consume).Data.(ptrace.Traces)) err = ctc.cancelAndWait() requireCanceledStatus(t, err) @@ -856,7 +856,10 @@ func TestReceiverEOF(t *testing.T) { actualData = append(actualData, (<-ctc.consume).Data.(ptrace.Traces)) } - assert.EqualValues(t, expectData, actualData) + assert.Equal(t, len(expectData), len(actualData)) + for i := 0; i < len(expectData); i++ { + assertEqualUnsortedSpans(t, expectData[i], actualData[i]) + } wg.Wait() } From 25366e0ba776db2efcb1f8e06768a097683e0f66 Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Fri, 3 May 2024 16:15:15 -0400 Subject: [PATCH 21/28] remove unneeded helper functions and use otelAssert.Equiv --- .../internal/arrow/arrow_test.go | 115 +++--------------- 1 file changed, 19 insertions(+), 96 deletions(-) diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go index 3c45bb87..b145ffd4 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go @@ -366,6 +366,7 @@ func requireCanceledStatus(t *testing.T, err error) { func TestBoundedQueueWithPdataHeaders(t *testing.T) { var sizer ptrace.ProtoMarshaler + stdTesting := otelAssert.NewStdUnitTest(t) pdataSizeTenTraces := sizer.TracesSize(testdata.GenerateTraces(10)) defaultBoundedQueueLimit := int64(100000) tests := []struct{ @@ -454,7 +455,11 @@ func TestBoundedQueueWithPdataHeaders(t *testing.T) { select { case data := <-ctc.consume: actualTD := data.Data.(ptrace.Traces) - assertEqualUnsortedSpans(t, td, actualTD) + otelAssert.Equiv(stdTesting, []json.Marshaler{ + compareJSONTraces{td}, + }, []json.Marshaler{ + compareJSONTraces{actualTD}, + }) err = ctc.cancelAndWait() requireCanceledStatus(t, err) case err = <-ctc.streamErr: @@ -464,100 +469,8 @@ func TestBoundedQueueWithPdataHeaders(t *testing.T) { } } -// order of spans might not be guaranteed, so sort the span objects by spanID and check equality. -func assertEqualUnsortedSpans(t *testing.T, a, b ptrace.Traces) { - assert.Equal(t, a.SpanCount(), b.SpanCount()) - - rssA := a.ResourceSpans() - rssB := b.ResourceSpans() - assert.Equal(t, rssA.Len(), rssB.Len()) - - rssA.Sort(sortResourceSpans) - rssB.Sort(sortResourceSpans) - for i := 0; i < rssA.Len(); i++ { - rsA := rssA.At(i) - rsB := rssB.At(i) - assert.Equal(t, rsA.Resource(), rsB.Resource()) - - sssA := rsA.ScopeSpans() - sssB := rsB.ScopeSpans() - assert.Equal(t, sssA.Len(), sssB.Len()) - - sssA.Sort(sortScopeSpans) - sssB.Sort(sortScopeSpans) - - for j := 0; j < sssA.Len(); j++ { - ssA := sssA.At(j) - ssB := sssB.At(j) - assert.Equal(t, ssA.Scope(), ssB.Scope()) - - spanSliceA := ssA.Spans() - spanSliceB := ssB.Spans() - assert.Equal(t, spanSliceA.Len(), spanSliceB.Len()) - - spanSliceA.Sort(sortSpans) - spanSliceB.Sort(sortSpans) - - assert.Equal(t, spanSliceA, spanSliceB) - } - } -} - -func sortResourceSpans(a, b ptrace.ResourceSpans) bool { - assl := a.ScopeSpans() - bssl := b.ScopeSpans() - - if assl.Len() == 0 { - return true - } - if bssl.Len() == 0 { - return false - } - - assl.Sort(sortScopeSpans) - bssl.Sort(sortScopeSpans) - - if assl.At(0).Spans().Len() == 0 { - return true - } - if bssl.At(0).Spans().Len() == 0 { - return false - } - - if assl.At(0).Spans().At(0).SpanID().String() < bssl.At(0).Spans().At(0).SpanID().String() { - return true - } - return false -} - -func sortScopeSpans(a, b ptrace.ScopeSpans) bool { - asl := a.Spans() - bsl := a.Spans() - - if asl.Len() == 0 { - return true - } - if bsl.Len() == 0 { - return false - } - - asl.Sort(sortSpans) - bsl.Sort(sortSpans) - - if asl.At(0).SpanID().String() < bsl.At(0).SpanID().String() { - return true - } - return false -} - -func sortSpans(a, b ptrace.Span) bool { - if a.SpanID().String() < b.SpanID().String() { - return true - } - return false -} - func TestReceiverTraces(t *testing.T) { + stdTesting := otelAssert.NewStdUnitTest(t) tc := healthyTestChannel{} ctc := newCommonTestCase(t, tc) @@ -570,7 +483,11 @@ func TestReceiverTraces(t *testing.T) { ctc.start(ctc.newRealConsumer, defaultBQ) ctc.putBatch(batch, nil) - assertEqualUnsortedSpans(t, td, (<-ctc.consume).Data.(ptrace.Traces)) + otelAssert.Equiv(stdTesting, []json.Marshaler{ + compareJSONTraces{td}, + }, []json.Marshaler{ + compareJSONTraces{(<-ctc.consume).Data.(ptrace.Traces)}, + }) err = ctc.cancelAndWait() requireCanceledStatus(t, err) @@ -816,6 +733,7 @@ func copyBatch(in *arrowpb.BatchArrowRecords) *arrowpb.BatchArrowRecords { func TestReceiverEOF(t *testing.T) { tc := healthyTestChannel{} ctc := newCommonTestCase(t, tc) + stdTesting := otelAssert.NewStdUnitTest(t) // send a sequence of data then simulate closing the connection. const times = 10 @@ -857,8 +775,13 @@ func TestReceiverEOF(t *testing.T) { } assert.Equal(t, len(expectData), len(actualData)) + for i := 0; i < len(expectData); i++ { - assertEqualUnsortedSpans(t, expectData[i], actualData[i]) + otelAssert.Equiv(stdTesting, []json.Marshaler{ + compareJSONTraces{expectData[i]}, + }, []json.Marshaler{ + compareJSONTraces{actualData[i]}, + }) } wg.Wait() From 40f7fa92e71c30c0d90354707cc4cb95c51f2ab8 Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Fri, 3 May 2024 16:21:43 -0400 Subject: [PATCH 22/28] update changelog --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3a63ba2..49cb0600 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,9 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## Unreleased -- Added a semaphore package to limit bytes admitted and total number of waiters. [#174](https://github.com/open-telemetry/otel-arrow/pull/174) +- Refactor otelarrowreceiver to do stream.Recv, request processing, and stream.Send in separate goroutines. [#181](https://github.com/open-telemetry/otel-arrow/pull/181) + +- Add a semaphore package to limit bytes admitted and total number of waiters. [#174](https://github.com/open-telemetry/otel-arrow/pull/174) ## [0.22.0](https://github.com/open-telemetry/otel-arrow/releases/tag/v0.22.0) - 2024-04-16 From 7db9a4042df32934b04b0fbf333f5beee0d960af Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Tue, 7 May 2024 18:50:38 -0400 Subject: [PATCH 23/28] improve readability with response.bytesToRelease --- .../otelarrowreceiver/internal/arrow/arrow.go | 85 +++++++++++-------- 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go index 8302fb15..307c5b63 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go @@ -343,7 +343,7 @@ type anyStreamServer interface { type batchResp struct { id int64 err error - uncompSz int64 + bytesToRelease int64 } func (r *Receiver) anyStream(serverStream anyStreamServer, method string) (retErr error) { @@ -444,6 +444,11 @@ func (r *Receiver) recvOne(ctx context.Context, serverStream anyStreamServer, hr return fmt.Errorf("breaking stream: %v", err) } + resp := batchResp{ + id: req.GetBatchId(), + bytesToRelease: int64(prevAcquiredBytes), + } + var authErr error if r.authServer != nil { var newCtx context.Context @@ -457,7 +462,9 @@ func (r *Receiver) recvOne(ctx context.Context, serverStream anyStreamServer, hr // processAndConsume will process and send an error to the sender loop go func() { defer r.inFlightWG.Done() // done processing - r.processAndConsume(thisCtx, method, ac, req, serverStream, authErr, pendingCh, int64(prevAcquiredBytes), sizeHeaderFound) + err = r.processAndConsume(thisCtx, method, ac, req, serverStream, authErr, resp, sizeHeaderFound) + resp.err = err + pendingCh <- resp }() return nil @@ -506,7 +513,7 @@ func (r *Receiver) sendOne(serverStream anyStreamServer, resp batchResp) error { r.logStreamError(err) return err } - r.boundedQueue.Release(resp.uncompSz) + r.boundedQueue.Release(resp.bytesToRelease) return nil } @@ -546,7 +553,7 @@ func (r *Receiver) srvSendLoop(ctx context.Context, serverStream anyStreamServer } } -func (r *Receiver) processAndConsume(ctx context.Context, method string, arrowConsumer arrowRecord.ConsumerAPI, req *arrowpb.BatchArrowRecords, serverStream anyStreamServer, authErr error, pendingCh chan<- batchResp, prevAcquiredBytes int64, sizeHeaderFound bool) { +func (r *Receiver) processAndConsume(ctx context.Context, method string, arrowConsumer arrowRecord.ConsumerAPI, req *arrowpb.BatchArrowRecords, serverStream anyStreamServer, authErr error, response batchResp, sizeHeaderFound bool) error { var err error ctx, span := r.tracer.Start(ctx, "otel_arrow_stream_recv") @@ -564,28 +571,23 @@ func (r *Receiver) processAndConsume(ctx context.Context, method string, arrowCo // Process records: an error in this code path does // not necessarily break the stream. - toRelease := prevAcquiredBytes if authErr != nil { err = authErr } else { - toRelease, err = r.processRecords(ctx, method, arrowConsumer, req, prevAcquiredBytes, sizeHeaderFound) + err = r.processRecords(ctx, method, arrowConsumer, req, response, sizeHeaderFound) } - pendingCh <- batchResp{ - id: req.GetBatchId(), - err: err, - uncompSz: toRelease, - } + return err } // processRecords returns an error and a boolean indicating whether // the error (true) was from processing the data (i.e., invalid // argument) or (false) from the consuming pipeline. The boolean is // not used when success (nil error) is returned. -func (r *Receiver) processRecords(ctx context.Context, method string, arrowConsumer arrowRecord.ConsumerAPI, records *arrowpb.BatchArrowRecords, prevAcquiredBytes int64, sizeHeaderFound bool) (int64, error) { +func (r *Receiver) processRecords(ctx context.Context, method string, arrowConsumer arrowRecord.ConsumerAPI, records *arrowpb.BatchArrowRecords, response batchResp, sizeHeaderFound bool) error { payloads := records.GetArrowPayloads() if len(payloads) == 0 { - return prevAcquiredBytes, nil + return nil } var uncompSize int64 if r.telemetry.MetricsLevel > configtelemetry.LevelNormal { @@ -607,7 +609,7 @@ func (r *Receiver) processRecords(ctx context.Context, method string, arrowConsu switch payloads[0].Type { case arrowpb.ArrowPayloadType_UNIVARIATE_METRICS: if r.Metrics() == nil { - return prevAcquiredBytes, status.Error(codes.Unimplemented, "metrics service not available") + return status.Error(codes.Unimplemented, "metrics service not available") } var sizer pmetric.ProtoMarshaler var numPts int @@ -632,12 +634,12 @@ func (r *Receiver) processRecords(ctx context.Context, method string, arrowConsu ) } - acquireErr := r.acquireAdditionalBytes(ctx, uncompSize, prevAcquiredBytes, sizeHeaderFound) + acquireErr := r.acquireAdditionalBytes(ctx, uncompSize, response, sizeHeaderFound) if acquireErr != nil { err = multierr.Append(err, acquireErr) // if acquireAdditionalBytes() failed then the previously acquired bytes were already released i.e. nothing to releaes. - return 0, err + return err } // entire request has been processed, decrement counter. @@ -645,11 +647,11 @@ func (r *Receiver) processRecords(ctx context.Context, method string, arrowConsu r.recvInFlightItems.Add(ctx, int64(-numPts)) } r.obsrecv.EndMetricsOp(ctx, streamFormat, numPts, err) - return uncompSize, err + return err case arrowpb.ArrowPayloadType_LOGS: if r.Logs() == nil { - return prevAcquiredBytes, status.Error(codes.Unimplemented, "logs service not available") + return status.Error(codes.Unimplemented, "logs service not available") } var sizer plog.ProtoMarshaler var numLogs int @@ -672,12 +674,12 @@ func (r *Receiver) processRecords(ctx context.Context, method string, arrowConsu ) } - acquireErr := r.acquireAdditionalBytes(ctx, uncompSize, prevAcquiredBytes, sizeHeaderFound) + acquireErr := r.acquireAdditionalBytes(ctx, uncompSize, response, sizeHeaderFound) if acquireErr != nil { err = multierr.Append(err, acquireErr) // if acquireAdditionalBytes() failed then the previously acquired bytes were already released i.e. nothing to releaes. - return 0, err + return err } // entire request has been processed, decrement counter. @@ -685,11 +687,11 @@ func (r *Receiver) processRecords(ctx context.Context, method string, arrowConsu r.recvInFlightItems.Add(ctx, int64(-numLogs)) } r.obsrecv.EndLogsOp(ctx, streamFormat, numLogs, err) - return uncompSize, err + return err case arrowpb.ArrowPayloadType_SPANS: if r.Traces() == nil { - return prevAcquiredBytes, status.Error(codes.Unimplemented, "traces service not available") + return status.Error(codes.Unimplemented, "traces service not available") } var sizer ptrace.ProtoMarshaler var numSpans int @@ -713,12 +715,12 @@ func (r *Receiver) processRecords(ctx context.Context, method string, arrowConsu ) } - acquireErr := r.acquireAdditionalBytes(ctx, uncompSize, prevAcquiredBytes, sizeHeaderFound) + acquireErr := r.acquireAdditionalBytes(ctx, uncompSize, response, sizeHeaderFound) if acquireErr != nil { err = multierr.Append(err, acquireErr) // if acquireAdditionalBytes() failed then the previously acquired bytes were already released i.e. nothing to releaes. - return 0, err + return err } // entire request has been processed, decrement counter. @@ -726,32 +728,43 @@ func (r *Receiver) processRecords(ctx context.Context, method string, arrowConsu r.recvInFlightItems.Add(ctx, int64(-numSpans)) } r.obsrecv.EndTracesOp(ctx, streamFormat, numSpans, err) - return uncompSize, err + return err default: - return prevAcquiredBytes, ErrUnrecognizedPayload + return ErrUnrecognizedPayload } } -func (r *Receiver) acquireAdditionalBytes(ctx context.Context, uncompSize int64, prevAcquiredBytes int64, sizeHeaderFound bool) error { - diff := uncompSize - prevAcquiredBytes +func (r *Receiver) acquireAdditionalBytes(ctx context.Context, uncompSize int64, response batchResp, sizeHeaderFound bool) error { + diff := uncompSize - response.bytesToRelease var err error if diff != 0 { if sizeHeaderFound { // a mismatch between header set by exporter and the uncompSize just calculated. - r.telemetry.Logger.Debug("mismatch between uncompressed size in receiver and otlp-pdata-size header", zap.Int("uncompsize", int(uncompSize)), zap.Int("otlp-pdata-size", int(prevAcquiredBytes))) - } else if diff < 0 { + r.telemetry.Logger.Debug("mismatch between uncompressed size in receiver and otlp-pdata-size header", zap.Int("uncompsize", int(uncompSize)), zap.Int("otlp-pdata-size", int(response.bytesToRelease))) + } else if diff < 0{ + // proto.Size() on compressed request was greater than pdata uncompressed size. - r.telemetry.Logger.Debug("uncompressed size is less than compressed size", zap.Int("uncompressed", int(uncompSize)), zap.Int("compressed", int(prevAcquiredBytes))) + r.telemetry.Logger.Debug("uncompressed size is less than compressed size", zap.Int("uncompressed", int(uncompSize)), zap.Int("compressed", int(response.bytesToRelease))) + } + + if diff > 0 { + // diff > 0 means we previously acquired too few bytes initially and we need to correct this. Release previously + // acquired bytes to prevent deadlock and reacquire the uncompressed size we just calculated. + // Note: No need to release and reacquire bytes if diff < 0 because this has less impact and no reason to potentially block + // a request that is in flight by reacquiring the correct size. + r.boundedQueue.Release(response.bytesToRelease) + err = r.boundedQueue.Acquire(ctx, uncompSize) + if err != nil { + response.bytesToRelease = int64(0) + } else { + response.bytesToRelease = uncompSize + } } - // regardless of the reason, if diff is not 0 then Release previously acquired bytes - // to prevent deadlock and reacquire the uncompressed size we just calculated. - r.boundedQueue.Release(prevAcquiredBytes) - err = r.boundedQueue.Acquire(ctx, uncompSize) + } return err } - From 8d45b907db1186c1f006afdaadae5babb05f7b12 Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Tue, 7 May 2024 19:03:36 -0400 Subject: [PATCH 24/28] remove deprecated --- collector/receiver/otelarrowreceiver/go.mod | 2 +- collector/receiver/otelarrowreceiver/go.sum | 10 +++++++++- .../receiver/otelarrowreceiver/internal/arrow/arrow.go | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/collector/receiver/otelarrowreceiver/go.mod b/collector/receiver/otelarrowreceiver/go.mod index 60abc223..bceb4b3e 100644 --- a/collector/receiver/otelarrowreceiver/go.mod +++ b/collector/receiver/otelarrowreceiver/go.mod @@ -28,6 +28,7 @@ require ( go.uber.org/zap v1.27.0 golang.org/x/net v0.24.0 google.golang.org/grpc v1.63.2 + google.golang.org/protobuf v1.33.0 ) require ( @@ -88,6 +89,5 @@ require ( golang.org/x/tools v0.15.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect - google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/collector/receiver/otelarrowreceiver/go.sum b/collector/receiver/otelarrowreceiver/go.sum index 5446808e..a0285322 100644 --- a/collector/receiver/otelarrowreceiver/go.sum +++ b/collector/receiver/otelarrowreceiver/go.sum @@ -7,10 +7,14 @@ github.com/apache/arrow/go/v14 v14.0.2 h1:N8OkaJEOfI3mEZt07BIkvo4sC6XDbL+48MBPWO github.com/apache/arrow/go/v14 v14.0.2/go.mod h1:u3fgh3EdgN/YQ8cVQRguVW3R+seMybFg8QBQ5LU+eBY= github.com/axiomhq/hyperloglog v0.0.0-20230201085229-3ddf4bad03dc h1:Keo7wQ7UODUaHcEi7ltENhbAK2VgZjfat6mLy03tQzo= github.com/axiomhq/hyperloglog v0.0.0-20230201085229-3ddf4bad03dc/go.mod h1:k08r+Yj1PRAmuayFiRK6MYuR5Ve4IuZtTfxErMIh0+c= +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/brianvoe/gofakeit/v6 v6.17.0 h1:obbQTJeHfktJtiZzq0Q1bEpsNUs+yHrYlPVWt7BtmJ4= github.com/brianvoe/gofakeit/v6 v6.17.0/go.mod h1:Ow6qC71xtwm79anlwKRlWZW6zVq9D2XHE4QSSMP/rU8= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -49,6 +53,7 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= @@ -70,6 +75,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= @@ -84,7 +91,6 @@ github.com/mostynb/go-grpc-compression v1.2.2/go.mod h1:GOCr2KBxXcblCuczg3YdLQlc github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/open-telemetry/otel-arrow v0.22.0 h1:G1jgtqAM2ho5pyKQ4tyrDzk9Y0VcJ+GZQRJgN26vRlI= github.com/open-telemetry/otel-arrow v0.22.0/go.mod h1:F50XFaiNfkfB0MYftZIUKFULm6pxfGqjbgQzevi+65M= -github.com/open-telemetry/otel-arrow/collector v0.22.0 h1:lHFjzkh5PbsiW8B63SRntnP9W7bLCXV9lslO4zI0s/Y= github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -104,6 +110,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= +github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go index 307c5b63..e25fc1fd 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go @@ -13,7 +13,6 @@ import ( "strings" "sync" - "github.com/golang/protobuf/proto" arrowpb "github.com/open-telemetry/otel-arrow/api/experimental/arrow/v1" "github.com/open-telemetry/otel-arrow/collector/netstats" arrowRecord "github.com/open-telemetry/otel-arrow/pkg/otel/arrow_record" @@ -41,6 +40,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" "github.com/open-telemetry/otel-arrow/collector/admission" ) From 8ea494910f1b1454b1fd1e00f85dfbfde8579fb3 Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Tue, 7 May 2024 19:06:50 -0400 Subject: [PATCH 25/28] gofmt --- .../internal/arrow/exporter_test.go | 6 +- .../receiver/otelarrowreceiver/config_test.go | 4 +- .../otelarrowreceiver/internal/arrow/arrow.go | 83 +++++++++---------- .../internal/arrow/arrow_test.go | 46 +++++----- 4 files changed, 68 insertions(+), 71 deletions(-) diff --git a/collector/exporter/otelarrowexporter/internal/arrow/exporter_test.go b/collector/exporter/otelarrowexporter/internal/arrow/exporter_test.go index acca740a..2740cdb1 100644 --- a/collector/exporter/otelarrowexporter/internal/arrow/exporter_test.go +++ b/collector/exporter/otelarrowexporter/internal/arrow/exporter_test.go @@ -602,8 +602,8 @@ func TestArrowExporterHeaders(t *testing.T) { if times%2 == 1 { md := metadata.MD{ - "expected1": []string{"metadata1"}, - "expected2": []string{fmt.Sprint(times)}, + "expected1": []string{"metadata1"}, + "expected2": []string{fmt.Sprint(times)}, "otlp-pdata-size": []string{"329"}, } expectOutput = append(expectOutput, md) @@ -680,7 +680,7 @@ func TestArrowExporterIsTraced(t *testing.T) { propagation.TraceContext{}.Inject(ctx, propagation.MapCarrier(expectMap)) md := metadata.MD{ - "traceparent": []string{expectMap["traceparent"]}, + "traceparent": []string{expectMap["traceparent"]}, "otlp-pdata-size": []string{"329"}, } expectOutput = append(expectOutput, md) diff --git a/collector/receiver/otelarrowreceiver/config_test.go b/collector/receiver/otelarrowreceiver/config_test.go index 659b11c8..7efbe884 100644 --- a/collector/receiver/otelarrowreceiver/config_test.go +++ b/collector/receiver/otelarrowreceiver/config_test.go @@ -77,7 +77,7 @@ func TestUnmarshalConfig(t *testing.T) { }, }, Arrow: ArrowConfig{ - MemoryLimitMiB: 123, + MemoryLimitMiB: 123, AdmissionLimitMiB: 80, }, }, @@ -102,7 +102,7 @@ func TestUnmarshalConfigUnix(t *testing.T) { ReadBufferSize: 512 * 1024, }, Arrow: ArrowConfig{ - MemoryLimitMiB: defaultMemoryLimitMiB, + MemoryLimitMiB: defaultMemoryLimitMiB, AdmissionLimitMiB: defaultAdmissionLimitMiB, }, }, diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go index e25fc1fd..7966619b 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go @@ -100,14 +100,14 @@ func New( tracer := set.TelemetrySettings.TracerProvider.Tracer("otel-arrow-receiver") var errors, err error recv := &Receiver{ - Consumers: cs, - obsrecv: obsrecv, - telemetry: set.TelemetrySettings, - tracer: tracer, - authServer: authServer, - newConsumer: newConsumer, - gsettings: gsettings, - netReporter: netReporter, + Consumers: cs, + obsrecv: obsrecv, + telemetry: set.TelemetrySettings, + tracer: tracer, + authServer: authServer, + newConsumer: newConsumer, + gsettings: gsettings, + netReporter: netReporter, boundedQueue: bq, } @@ -341,8 +341,8 @@ type anyStreamServer interface { } type batchResp struct { - id int64 - err error + id int64 + err error bytesToRelease int64 } @@ -384,9 +384,8 @@ func (r *Receiver) anyStream(serverStream anyStreamServer, method string) (retEr senderWG.Done() }() - select { - case <-doneCtx.Done(): + case <-doneCtx.Done(): senderWG.Wait() return status.Error(codes.Canceled, "server stream shutdown") case retErr = <-streamErrCh: @@ -405,7 +404,6 @@ func (r *Receiver) recvOne(ctx context.Context, serverStream anyStreamServer, hr } }() - // Receive a batch corresponding with one ptrace.Traces, pmetric.Metrics, // or plog.Logs item. req, err := serverStream.Recv() @@ -445,7 +443,7 @@ func (r *Receiver) recvOne(ctx context.Context, serverStream anyStreamServer, hr } resp := batchResp{ - id: req.GetBatchId(), + id: req.GetBatchId(), bytesToRelease: int64(prevAcquiredBytes), } @@ -486,36 +484,36 @@ func (r *Receiver) srvReceiveLoop(ctx context.Context, serverStream anyStreamSer } func (r *Receiver) sendOne(serverStream anyStreamServer, resp batchResp) error { - // Note: Statuses can be batched, but we do not take - // advantage of this feature. - status := &arrowpb.BatchStatus{ - BatchId: resp.id, - } - if resp.err == nil { - status.StatusCode = arrowpb.StatusCode_OK - } else { - status.StatusMessage = resp.err.Error() - switch { - case errors.Is(resp.err, arrowRecord.ErrConsumerMemoryLimit): - r.telemetry.Logger.Error("arrow resource exhausted", zap.Error(resp.err)) - status.StatusCode = arrowpb.StatusCode_RESOURCE_EXHAUSTED - case consumererror.IsPermanent(resp.err): - r.telemetry.Logger.Error("arrow data error", zap.Error(resp.err)) - status.StatusCode = arrowpb.StatusCode_INVALID_ARGUMENT - default: - r.telemetry.Logger.Debug("arrow consumer error", zap.Error(resp.err)) - status.StatusCode = arrowpb.StatusCode_UNAVAILABLE - } + // Note: Statuses can be batched, but we do not take + // advantage of this feature. + status := &arrowpb.BatchStatus{ + BatchId: resp.id, + } + if resp.err == nil { + status.StatusCode = arrowpb.StatusCode_OK + } else { + status.StatusMessage = resp.err.Error() + switch { + case errors.Is(resp.err, arrowRecord.ErrConsumerMemoryLimit): + r.telemetry.Logger.Error("arrow resource exhausted", zap.Error(resp.err)) + status.StatusCode = arrowpb.StatusCode_RESOURCE_EXHAUSTED + case consumererror.IsPermanent(resp.err): + r.telemetry.Logger.Error("arrow data error", zap.Error(resp.err)) + status.StatusCode = arrowpb.StatusCode_INVALID_ARGUMENT + default: + r.telemetry.Logger.Debug("arrow consumer error", zap.Error(resp.err)) + status.StatusCode = arrowpb.StatusCode_UNAVAILABLE } + } - err := serverStream.Send(status) - if err != nil { - r.logStreamError(err) - return err - } - r.boundedQueue.Release(resp.bytesToRelease) + err := serverStream.Send(status) + if err != nil { + r.logStreamError(err) + return err + } + r.boundedQueue.Release(resp.bytesToRelease) - return nil + return nil } func (r *Receiver) flushSender(serverStream anyStreamServer, pendingCh <-chan batchResp) error { @@ -743,7 +741,7 @@ func (r *Receiver) acquireAdditionalBytes(ctx context.Context, uncompSize int64, if sizeHeaderFound { // a mismatch between header set by exporter and the uncompSize just calculated. r.telemetry.Logger.Debug("mismatch between uncompressed size in receiver and otlp-pdata-size header", zap.Int("uncompsize", int(uncompSize)), zap.Int("otlp-pdata-size", int(response.bytesToRelease))) - } else if diff < 0{ + } else if diff < 0 { // proto.Size() on compressed request was greater than pdata uncompressed size. r.telemetry.Logger.Debug("uncompressed size is less than compressed size", zap.Int("uncompressed", int(uncompSize)), zap.Int("compressed", int(response.bytesToRelease))) @@ -763,7 +761,6 @@ func (r *Receiver) acquireAdditionalBytes(ctx context.Context, uncompSize int64, } } - } return err diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go index b145ffd4..530bb35a 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow_test.go @@ -369,49 +369,49 @@ func TestBoundedQueueWithPdataHeaders(t *testing.T) { stdTesting := otelAssert.NewStdUnitTest(t) pdataSizeTenTraces := sizer.TracesSize(testdata.GenerateTraces(10)) defaultBoundedQueueLimit := int64(100000) - tests := []struct{ - name string - numTraces int + tests := []struct { + name string + numTraces int includePdataHeader bool - pdataSize string - rejected bool + pdataSize string + rejected bool }{ { - name: "no header compressed greater than uncompressed", + name: "no header compressed greater than uncompressed", numTraces: 10, }, { - name: "no header compressed less than uncompressed", + name: "no header compressed less than uncompressed", numTraces: 100, }, { - name: "pdata header less than uncompressedSize", - numTraces: 10, - pdataSize: strconv.Itoa(pdataSizeTenTraces / 2), + name: "pdata header less than uncompressedSize", + numTraces: 10, + pdataSize: strconv.Itoa(pdataSizeTenTraces / 2), includePdataHeader: true, }, { - name: "pdata header equal uncompressedSize", - numTraces: 10, - pdataSize: strconv.Itoa(pdataSizeTenTraces), + name: "pdata header equal uncompressedSize", + numTraces: 10, + pdataSize: strconv.Itoa(pdataSizeTenTraces), includePdataHeader: true, }, { - name: "pdata header greater than uncompressedSize", - numTraces: 10, - pdataSize: strconv.Itoa(pdataSizeTenTraces * 2), + name: "pdata header greater than uncompressedSize", + numTraces: 10, + pdataSize: strconv.Itoa(pdataSizeTenTraces * 2), includePdataHeader: true, }, { - name: "no header compressed accepted uncompressed rejected", + name: "no header compressed accepted uncompressed rejected", numTraces: 100, - rejected: true, + rejected: true, }, { - name: "pdata header accepted uncompressed rejected", - numTraces: 100, - rejected: true, - pdataSize: strconv.Itoa(pdataSizeTenTraces), + name: "pdata header accepted uncompressed rejected", + numTraces: 100, + rejected: true, + pdataSize: strconv.Itoa(pdataSizeTenTraces), includePdataHeader: true, }, } @@ -439,7 +439,7 @@ func TestBoundedQueueWithPdataHeaders(t *testing.T) { if tt.rejected { ctc.stream.EXPECT().Send(statusUnavailableFor(batch.BatchId, "rejecting request, request size larger than configured limit")).Times(1).Return(fmt.Errorf("rejecting request, request size larger than configured limit")) // make the boundedqueue limit be slightly less than the uncompressed size - bq = admission.NewBoundedQueue(int64(sizer.TracesSize(td) - 100), int64(10)) + bq = admission.NewBoundedQueue(int64(sizer.TracesSize(td)-100), int64(10)) } else { ctc.stream.EXPECT().Send(statusOKFor(batch.BatchId)).Times(1).Return(nil) bq = admission.NewBoundedQueue(defaultBoundedQueueLimit, int64(10)) From aacba4edb53e6a4cffa0ecd9354d0892b1114191 Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Tue, 7 May 2024 19:09:27 -0400 Subject: [PATCH 26/28] rm newline --- collector/receiver/otelarrowreceiver/internal/arrow/arrow.go | 1 - 1 file changed, 1 deletion(-) diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go index 7966619b..a4f608c0 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go @@ -742,7 +742,6 @@ func (r *Receiver) acquireAdditionalBytes(ctx context.Context, uncompSize int64, // a mismatch between header set by exporter and the uncompSize just calculated. r.telemetry.Logger.Debug("mismatch between uncompressed size in receiver and otlp-pdata-size header", zap.Int("uncompsize", int(uncompSize)), zap.Int("otlp-pdata-size", int(response.bytesToRelease))) } else if diff < 0 { - // proto.Size() on compressed request was greater than pdata uncompressed size. r.telemetry.Logger.Debug("uncompressed size is less than compressed size", zap.Int("uncompressed", int(uncompSize)), zap.Int("compressed", int(response.bytesToRelease))) } From b97b100fb3f6a1e263f52afa060cd6180a62e5d9 Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Tue, 7 May 2024 19:24:30 -0400 Subject: [PATCH 27/28] go mod tidy --- collector/go.mod | 1 - collector/go.sum | 2 -- 2 files changed, 3 deletions(-) diff --git a/collector/go.mod b/collector/go.mod index 44cf226a..3e54d0a8 100644 --- a/collector/go.mod +++ b/collector/go.mod @@ -32,7 +32,6 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/protobuf v1.5.4 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/knadh/koanf/maps v0.1.1 // indirect github.com/knadh/koanf/providers/confmap v0.1.0 // indirect diff --git a/collector/go.sum b/collector/go.sum index 5294b86a..982108ba 100644 --- a/collector/go.sum +++ b/collector/go.sum @@ -18,8 +18,6 @@ github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 h1:TQcrn6Wq+sKGkpyPvppOz99zsM github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= From e9e2d3166044786334527f7a20c3a341318fd09c Mon Sep 17 00:00:00 2001 From: moh-osman3 Date: Thu, 9 May 2024 09:49:44 -0400 Subject: [PATCH 28/28] add client address if available --- .../receiver/otelarrowreceiver/internal/arrow/arrow.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go index a4f608c0..6fbafb57 100644 --- a/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go +++ b/collector/receiver/otelarrowreceiver/internal/arrow/arrow.go @@ -8,6 +8,7 @@ import ( "errors" "fmt" "io" + "net" "runtime" "strconv" "strings" @@ -341,6 +342,7 @@ type anyStreamServer interface { } type batchResp struct { + addr net.Addr id int64 err error bytesToRelease int64 @@ -443,6 +445,7 @@ func (r *Receiver) recvOne(ctx context.Context, serverStream anyStreamServer, hr } resp := batchResp{ + addr: hrcv.connInfo.Addr, id: req.GetBatchId(), bytesToRelease: int64(prevAcquiredBytes), } @@ -739,8 +742,12 @@ func (r *Receiver) acquireAdditionalBytes(ctx context.Context, uncompSize int64, var err error if diff != 0 { if sizeHeaderFound { + var clientAddr string + if response.addr != nil { + clientAddr = response.addr.String() + } // a mismatch between header set by exporter and the uncompSize just calculated. - r.telemetry.Logger.Debug("mismatch between uncompressed size in receiver and otlp-pdata-size header", zap.Int("uncompsize", int(uncompSize)), zap.Int("otlp-pdata-size", int(response.bytesToRelease))) + r.telemetry.Logger.Debug("mismatch between uncompressed size in receiver and otlp-pdata-size header", zap.String("client-address", clientAddr), zap.Int("uncompsize", int(uncompSize)), zap.Int("otlp-pdata-size", int(response.bytesToRelease))) } else if diff < 0 { // proto.Size() on compressed request was greater than pdata uncompressed size. r.telemetry.Logger.Debug("uncompressed size is less than compressed size", zap.Int("uncompressed", int(uncompSize)), zap.Int("compressed", int(response.bytesToRelease)))