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: &timestamppb.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: &timestamppb.Timestamp{Seconds: 
1234567890, Nanos: 123456789}}},
+               },
+               {
+                       name: "timestamp value with high precision",
+                       src:  &modelv1.TagValue{Value: 
&modelv1.TagValue_Timestamp{Timestamp: &timestamppb.Timestamp{Seconds: 0, 
Nanos: 999999999}}},
+               },
                {
                        name: "unsupported type",
                        src:  &modelv1.TagValue{Value: 
&modelv1.TagValue_Null{}},

Reply via email to