This is an automated email from the ASF dual-hosted git repository. hanahmily pushed a commit to branch trace/liaison in repository https://gitbox.apache.org/repos/asf/skywalking-banyandb.git
commit ef83764bb6fb9ad9286bc46441fd6f910efc2fcd Author: Gao Hongtao <hanahm...@gmail.com> AuthorDate: Thu Aug 28 20:09:41 2025 +0800 Enhance tag value handling in model and tests - Removed the unused `mustEncodeTagValue` function from the trace query implementation, streamlining the code. - Introduced support for timestamp values in the `modelv1.TagValue` structure, including serialization and deserialization logic. - Updated tests to cover new timestamp value scenarios, ensuring comprehensive validation of tag value handling. --- banyand/trace/query.go | 12 ------------ pkg/pb/v1/value.go | 42 ++++++++++++++++++++++++++++++++++++++++++ pkg/pb/v1/value_test.go | 9 +++++++++ 3 files changed, 51 insertions(+), 12 deletions(-) diff --git a/banyand/trace/query.go b/banyand/trace/query.go index df81f15c..88ede3b9 100644 --- a/banyand/trace/query.go +++ b/banyand/trace/query.go @@ -25,7 +25,6 @@ import ( "github.com/pkg/errors" - databasev1 "github.com/apache/skywalking-banyandb/api/proto/banyandb/database/v1" modelv1 "github.com/apache/skywalking-banyandb/api/proto/banyandb/model/v1" "github.com/apache/skywalking-banyandb/banyand/internal/storage" "github.com/apache/skywalking-banyandb/pkg/convert" @@ -310,17 +309,6 @@ func (qr *queryResult) merge() *model.TraceResult { return result } -func mustEncodeTagValue(name string, tagType databasev1.TagType, tagValue *modelv1.TagValue, num int) [][]byte { - values := make([][]byte, num) - tv := encodeTagValue(name, tagType, tagValue) - defer releaseTagValue(tv) - value := tv.marshal() - for i := 0; i < num; i++ { - values[i] = value - } - return values -} - func mustDecodeTagValue(valueType pbv1.ValueType, value []byte) *modelv1.TagValue { if value == nil { return pbv1.NullTagValue diff --git a/pkg/pb/v1/value.go b/pkg/pb/v1/value.go index f13fc161..9d2eea50 100644 --- a/pkg/pb/v1/value.go +++ b/pkg/pb/v1/value.go @@ -23,6 +23,7 @@ import ( "strconv" "github.com/pkg/errors" + "google.golang.org/protobuf/types/known/timestamppb" databasev1 "github.com/apache/skywalking-banyandb/api/proto/banyandb/database/v1" modelv1 "github.com/apache/skywalking-banyandb/api/proto/banyandb/model/v1" @@ -43,6 +44,7 @@ const ( ValueTypeBinaryData ValueTypeStrArr ValueTypeInt64Arr + ValueTypeTimestamp ) // MustTagValueToValueType converts modelv1.TagValue to ValueType. @@ -60,6 +62,8 @@ func MustTagValueToValueType(tag *modelv1.TagValue) ValueType { return ValueTypeStrArr case *modelv1.TagValue_IntArray: return ValueTypeInt64Arr + case *modelv1.TagValue_Timestamp: + return ValueTypeTimestamp default: panic("unknown tag value type") } @@ -78,6 +82,8 @@ func MustTagValueSpecToValueType(tag databasev1.TagType) ValueType { return ValueTypeStrArr case databasev1.TagType_TAG_TYPE_INT_ARRAY: return ValueTypeInt64Arr + case databasev1.TagType_TAG_TYPE_TIMESTAMP: + return ValueTypeTimestamp default: panic("unknown tag value type") } @@ -92,6 +98,8 @@ func MustTagValueToStr(tag *modelv1.TagValue) string { return strconv.FormatInt(tag.GetInt().Value, 10) case *modelv1.TagValue_BinaryData: return fmt.Sprintf("%x", tag.GetBinaryData()) + case *modelv1.TagValue_Timestamp: + return tag.GetTimestamp().String() default: panic("unknown tag value type") } @@ -135,6 +143,12 @@ func marshalTagValue(dest []byte, tv *modelv1.TagValue) ([]byte, error) { dest = marshalEntityValue(dest, encoding.Int64ToBytes(nil, tv.GetInt().Value)) case *modelv1.TagValue_BinaryData: dest = marshalEntityValue(dest, tv.GetBinaryData()) + case *modelv1.TagValue_Timestamp: + // Convert timestamp to 64-bit nanoseconds since epoch for efficient storage + ts := tv.GetTimestamp() + epochNanos := ts.Seconds*1e9 + int64(ts.Nanos) + tsBytes := encoding.Int64ToBytes(nil, epochNanos) + dest = marshalEntityValue(dest, tsBytes) default: return nil, errors.New("unsupported tag value type: " + tv.String()) } @@ -198,6 +212,25 @@ func unmarshalTagValue(dest []byte, src []byte) ([]byte, []byte, *modelv1.TagVal BinaryData: data, }, }, nil + case ValueTypeTimestamp: + if dest, src, err = unmarshalEntityValue(dest, src[1:]); err != nil { + return nil, nil, nil, errors.WithMessage(err, "unmarshal timestamp tag value") + } + // Unmarshal 64-bit epoch nanoseconds and convert back to seconds + nanos + if len(dest) < 8 { // Need at least 8 bytes for the 64-bit value + return nil, src, nil, errors.New("insufficient bytes for timestamp") + } + epochNanos := encoding.BytesToInt64(dest) + seconds := epochNanos / 1e9 + nanos := int32(epochNanos % 1e9) + return dest, src, &modelv1.TagValue{ + Value: &modelv1.TagValue_Timestamp{ + Timestamp: ×tamppb.Timestamp{ + Seconds: seconds, + Nanos: nanos, + }, + }, + }, nil default: return nil, src, nil, fmt.Errorf("unsupported tag value type %d, tag value: %s", vt, src) } @@ -286,6 +319,15 @@ func MustCompareTagValue(tv1, tv2 *modelv1.TagValue) int { return int(tv1.GetInt().Value - tv2.GetInt().Value) case ValueTypeBinaryData: return bytes.Compare(tv1.GetBinaryData(), tv2.GetBinaryData()) + case ValueTypeTimestamp: + ts1 := tv1.GetTimestamp() + ts2 := tv2.GetTimestamp() + if ts1.Seconds < ts2.Seconds { + return -1 + } else if ts1.Seconds > ts2.Seconds { + return 1 + } + return 0 default: logger.Panicf("unsupported tag value type: %v", vt1) return 0 diff --git a/pkg/pb/v1/value_test.go b/pkg/pb/v1/value_test.go index 710fb2cf..6eeae75d 100644 --- a/pkg/pb/v1/value_test.go +++ b/pkg/pb/v1/value_test.go @@ -21,6 +21,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "google.golang.org/protobuf/types/known/timestamppb" modelv1 "github.com/apache/skywalking-banyandb/api/proto/banyandb/model/v1" ) @@ -42,6 +43,14 @@ func TestMarshalAndUnmarshalTagValue(t *testing.T) { name: "binary data", src: &modelv1.TagValue{Value: &modelv1.TagValue_BinaryData{BinaryData: []byte("binaryData")}}, }, + { + name: "timestamp value", + src: &modelv1.TagValue{Value: &modelv1.TagValue_Timestamp{Timestamp: ×tamppb.Timestamp{Seconds: 1234567890, Nanos: 123456789}}}, + }, + { + name: "timestamp value with high precision", + src: &modelv1.TagValue{Value: &modelv1.TagValue_Timestamp{Timestamp: ×tamppb.Timestamp{Seconds: 0, Nanos: 999999999}}}, + }, { name: "unsupported type", src: &modelv1.TagValue{Value: &modelv1.TagValue_Null{}},