github.com/ydb-platform/ydb-go-sdk/v3@v3.89.2/internal/grpcwrapper/rawtopic/rawtopicwriter/messages.go (about)

     1  package rawtopicwriter
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"reflect"
     7  	"strconv"
     8  	"time"
     9  
    10  	"github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Topic"
    11  	"google.golang.org/protobuf/types/known/timestamppb"
    12  
    13  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/grpcwrapper/rawtopic/rawtopiccommon"
    14  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
    15  )
    16  
    17  var (
    18  	errWriteResultProtoIsNil             = xerrors.Wrap(errors.New("ydb: write result proto is nil"))
    19  	errWriteResultResponseWriteAckIsNil  = xerrors.Wrap(errors.New("ydb: write result response write ack is nil"))
    20  	errWriteResultResponseStatisticIsNil = xerrors.Wrap(errors.New("ydb: write result response statistic is nil"))
    21  )
    22  
    23  type InitRequest struct {
    24  	clientMessageImpl
    25  
    26  	Path             string
    27  	ProducerID       string
    28  	WriteSessionMeta map[string]string
    29  
    30  	Partitioning Partitioning
    31  
    32  	GetLastSeqNo bool
    33  }
    34  
    35  func (r *InitRequest) toProto() (*Ydb_Topic.StreamWriteMessage_InitRequest, error) {
    36  	res := &Ydb_Topic.StreamWriteMessage_InitRequest{
    37  		Path:             r.Path,
    38  		ProducerId:       r.ProducerID,
    39  		WriteSessionMeta: r.WriteSessionMeta,
    40  		GetLastSeqNo:     r.GetLastSeqNo,
    41  	}
    42  
    43  	err := r.Partitioning.setToProtoInitRequest(res)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  
    48  	return res, nil
    49  }
    50  
    51  // Partitioning is struct because it included in per-message structure and
    52  // places on hot-path for write messages
    53  // structure will work and compile-optimization better then interface
    54  type Partitioning struct {
    55  	Type           PartitioningType
    56  	MessageGroupID string
    57  	PartitionID    int64
    58  }
    59  
    60  func NewPartitioningMessageGroup(messageGroupID string) Partitioning {
    61  	return Partitioning{
    62  		Type:           PartitioningMessageGroupID,
    63  		MessageGroupID: messageGroupID,
    64  	}
    65  }
    66  
    67  func NewPartitioningPartitionID(partitionID int64) Partitioning {
    68  	return Partitioning{
    69  		Type:        PartitioningPartitionID,
    70  		PartitionID: partitionID,
    71  	}
    72  }
    73  
    74  func (p *Partitioning) setToProtoInitRequest(r *Ydb_Topic.StreamWriteMessage_InitRequest) error {
    75  	switch p.Type {
    76  	case PartitioningUndefined:
    77  		r.Partitioning = nil
    78  	case PartitioningMessageGroupID:
    79  		r.Partitioning = &Ydb_Topic.StreamWriteMessage_InitRequest_MessageGroupId{
    80  			MessageGroupId: p.MessageGroupID,
    81  		}
    82  	case PartitioningPartitionID:
    83  		r.Partitioning = &Ydb_Topic.StreamWriteMessage_InitRequest_PartitionId{
    84  			PartitionId: p.PartitionID,
    85  		}
    86  	default:
    87  		return xerrors.WithStackTrace(xerrors.Wrap(fmt.Errorf(
    88  			"ydb: unexpected partition type while set to init request: %v",
    89  			p.Type,
    90  		)))
    91  	}
    92  
    93  	return nil
    94  }
    95  
    96  func (p *Partitioning) setToProtoMessage(m *Ydb_Topic.StreamWriteMessage_WriteRequest_MessageData) error {
    97  	switch p.Type {
    98  	case PartitioningUndefined:
    99  		m.Partitioning = nil
   100  	case PartitioningMessageGroupID:
   101  		m.Partitioning = &Ydb_Topic.StreamWriteMessage_WriteRequest_MessageData_MessageGroupId{
   102  			MessageGroupId: p.MessageGroupID,
   103  		}
   104  	case PartitioningPartitionID:
   105  		m.Partitioning = &Ydb_Topic.StreamWriteMessage_WriteRequest_MessageData_PartitionId{
   106  			PartitionId: p.PartitionID,
   107  		}
   108  	default:
   109  		return xerrors.WithStackTrace(xerrors.Wrap(fmt.Errorf(
   110  			"ydb: unexpected partition type while set to message proto: %v",
   111  			p.Type,
   112  		)))
   113  	}
   114  
   115  	return nil
   116  }
   117  
   118  type PartitioningType int
   119  
   120  const (
   121  	PartitioningUndefined PartitioningType = iota
   122  	PartitioningMessageGroupID
   123  	PartitioningPartitionID
   124  )
   125  
   126  type InitResult struct {
   127  	serverMessageImpl
   128  	rawtopiccommon.ServerMessageMetadata
   129  
   130  	LastSeqNo       int64
   131  	SessionID       string
   132  	PartitionID     int64
   133  	SupportedCodecs rawtopiccommon.SupportedCodecs
   134  }
   135  
   136  func (r *InitResult) mustFromProto(response *Ydb_Topic.StreamWriteMessage_InitResponse) {
   137  	r.SessionID = response.GetSessionId()
   138  	r.PartitionID = response.GetPartitionId()
   139  	r.LastSeqNo = response.GetLastSeqNo()
   140  	r.SupportedCodecs.MustFromProto(response.GetSupportedCodecs())
   141  }
   142  
   143  type WriteRequest struct {
   144  	clientMessageImpl
   145  
   146  	Messages []MessageData
   147  	Codec    rawtopiccommon.Codec
   148  	Tx       rawtopiccommon.TransactionIdentity
   149  }
   150  
   151  func (r *WriteRequest) toProto() (p *Ydb_Topic.StreamWriteMessage_FromClient_WriteRequest, err error) {
   152  	messages := make([]*Ydb_Topic.StreamWriteMessage_WriteRequest_MessageData, len(r.Messages))
   153  
   154  	for i := range r.Messages {
   155  		messages[i], err = r.Messages[i].ToProto()
   156  		if err != nil {
   157  			return nil, err
   158  		}
   159  	}
   160  
   161  	res := &Ydb_Topic.StreamWriteMessage_FromClient_WriteRequest{
   162  		WriteRequest: &Ydb_Topic.StreamWriteMessage_WriteRequest{
   163  			Messages: messages,
   164  			Codec:    int32(r.Codec.ToProto()),
   165  			Tx:       r.Tx.ToProto(),
   166  		},
   167  	}
   168  
   169  	return res, nil
   170  }
   171  
   172  type MessageData struct {
   173  	SeqNo            int64
   174  	CreatedAt        time.Time
   175  	UncompressedSize int64
   176  	Partitioning     Partitioning
   177  	MetadataItems    []rawtopiccommon.MetadataItem
   178  	Data             []byte
   179  }
   180  
   181  func (d *MessageData) ToProto() (*Ydb_Topic.StreamWriteMessage_WriteRequest_MessageData, error) {
   182  	res := &Ydb_Topic.StreamWriteMessage_WriteRequest_MessageData{
   183  		SeqNo:            d.SeqNo,
   184  		CreatedAt:        timestamppb.New(d.CreatedAt),
   185  		Data:             d.Data,
   186  		UncompressedSize: d.UncompressedSize,
   187  	}
   188  	err := d.Partitioning.setToProtoMessage(res)
   189  	if err != nil {
   190  		return nil, err
   191  	}
   192  
   193  	for i := range d.MetadataItems {
   194  		res.MetadataItems = append(res.GetMetadataItems(), &Ydb_Topic.MetadataItem{
   195  			Key:   d.MetadataItems[i].Key,
   196  			Value: d.MetadataItems[i].Value,
   197  		})
   198  	}
   199  
   200  	return res, nil
   201  }
   202  
   203  type WriteResult struct {
   204  	serverMessageImpl
   205  	rawtopiccommon.ServerMessageMetadata
   206  
   207  	Acks            []WriteAck
   208  	PartitionID     int64
   209  	WriteStatistics WriteStatistics
   210  }
   211  
   212  func (r *WriteResult) fromProto(response *Ydb_Topic.StreamWriteMessage_WriteResponse) error {
   213  	if response == nil {
   214  		return xerrors.WithStackTrace(errWriteResultProtoIsNil)
   215  	}
   216  	r.Acks = make([]WriteAck, len(response.GetAcks()))
   217  	for i := range response.GetAcks() {
   218  		if err := r.Acks[i].fromProto(response.GetAcks()[i]); err != nil {
   219  			return err
   220  		}
   221  	}
   222  	r.PartitionID = response.GetPartitionId()
   223  
   224  	return r.WriteStatistics.fromProto(response.GetWriteStatistics())
   225  }
   226  
   227  // GetAcks implemtnts trace.TopicWriterResultMessagesInfoAcks interface
   228  func (r *WriteResult) GetAcks() (res traceAck) {
   229  	res.AcksCount = len(r.Acks)
   230  	if res.AcksCount > 0 {
   231  		res.SeqNoMin = r.Acks[0].SeqNo
   232  		res.WrittenOffsetMin = r.Acks[0].MessageWriteStatus.WrittenOffset
   233  	}
   234  	for i := range r.Acks {
   235  		ack := &r.Acks[i]
   236  		switch ack.MessageWriteStatus.Type {
   237  		case WriteStatusTypeWritten:
   238  			res.WrittenCount++
   239  		case WriteStatusTypeSkipped:
   240  			res.SkipCount++
   241  		case WriteStatusTypeWrittenInTx:
   242  			res.WrittenInTxCount++
   243  		}
   244  
   245  		if ack.SeqNo < res.SeqNoMin {
   246  			res.SeqNoMin = ack.SeqNo
   247  		} else if ack.SeqNo > res.SeqNoMax {
   248  			res.SeqNoMax = ack.SeqNo
   249  		}
   250  
   251  		if ack.MessageWriteStatus.WrittenOffset < res.SeqNoMin {
   252  			res.WrittenOffsetMin = ack.MessageWriteStatus.WrittenOffset
   253  		} else if ack.MessageWriteStatus.WrittenOffset > res.WrittenOffsetMax {
   254  			res.WrittenOffsetMax = ack.MessageWriteStatus.WrittenOffset
   255  		}
   256  	}
   257  
   258  	return res
   259  }
   260  
   261  type traceAck = struct {
   262  	AcksCount        int
   263  	SeqNoMin         int64
   264  	SeqNoMax         int64
   265  	WrittenOffsetMin int64
   266  	WrittenOffsetMax int64
   267  	WrittenCount     int
   268  	WrittenInTxCount int
   269  	SkipCount        int
   270  }
   271  
   272  type WriteAck struct {
   273  	SeqNo              int64
   274  	MessageWriteStatus MessageWriteStatus
   275  }
   276  
   277  func (wa *WriteAck) fromProto(pb *Ydb_Topic.StreamWriteMessage_WriteResponse_WriteAck) error {
   278  	if pb == nil {
   279  		return xerrors.WithStackTrace(errWriteResultResponseWriteAckIsNil)
   280  	}
   281  	wa.SeqNo = pb.GetSeqNo()
   282  
   283  	return wa.MessageWriteStatus.fromProto(pb.GetMessageWriteStatus())
   284  }
   285  
   286  // MessageWriteStatus is struct because it included in per-message structure and
   287  // places on hot-path for write messages
   288  // structure will work and compile-optimization better then interface
   289  type MessageWriteStatus struct {
   290  	Type          WriteStatusType
   291  	WrittenOffset int64
   292  	SkippedReason WriteStatusSkipReason
   293  }
   294  
   295  func (s *MessageWriteStatus) fromProto(status interface{}) error {
   296  	switch v := status.(type) {
   297  	case *Ydb_Topic.StreamWriteMessage_WriteResponse_WriteAck_Written_:
   298  		s.Type = WriteStatusTypeWritten
   299  		s.WrittenOffset = v.Written.GetOffset()
   300  
   301  		return nil
   302  	case *Ydb_Topic.StreamWriteMessage_WriteResponse_WriteAck_Skipped_:
   303  		s.Type = WriteStatusTypeSkipped
   304  		s.SkippedReason = WriteStatusSkipReason(v.Skipped.GetReason())
   305  
   306  		return nil
   307  
   308  	case *Ydb_Topic.StreamWriteMessage_WriteResponse_WriteAck_WrittenInTx_:
   309  		s.Type = WriteStatusTypeWrittenInTx
   310  
   311  		return nil
   312  
   313  	default:
   314  		return xerrors.WithStackTrace(xerrors.Wrap(fmt.Errorf("ydb: unexpected write status type: %v", reflect.TypeOf(v))))
   315  	}
   316  }
   317  
   318  type WriteStatusType int
   319  
   320  const (
   321  	WriteStatusTypeWritten WriteStatusType = iota + 1
   322  	WriteStatusTypeSkipped
   323  	WriteStatusTypeWrittenInTx
   324  )
   325  
   326  func (t WriteStatusType) String() string {
   327  	switch t {
   328  	case WriteStatusTypeSkipped:
   329  		return "Skipped"
   330  	case WriteStatusTypeWritten:
   331  		return "Written"
   332  	case WriteStatusTypeWrittenInTx:
   333  		return "WrittenInTx"
   334  	default:
   335  		return strconv.Itoa(int(t))
   336  	}
   337  }
   338  
   339  type WriteStatusSkipReason int
   340  
   341  const (
   342  	WriteStatusSkipReasonUnspecified    = WriteStatusSkipReason(Ydb_Topic.StreamWriteMessage_WriteResponse_WriteAck_Skipped_REASON_UNSPECIFIED)     //nolint:lll
   343  	WriteStatusSkipReasonAlreadyWritten = WriteStatusSkipReason(Ydb_Topic.StreamWriteMessage_WriteResponse_WriteAck_Skipped_REASON_ALREADY_WRITTEN) //nolint:lll
   344  )
   345  
   346  type WriteStatistics struct {
   347  	PersistingTime     time.Duration
   348  	MinQueueWaitTime   time.Duration
   349  	MaxQueueWaitTime   time.Duration
   350  	TopicQuotaWaitTime time.Duration
   351  }
   352  
   353  func (s *WriteStatistics) fromProto(statistics *Ydb_Topic.StreamWriteMessage_WriteResponse_WriteStatistics) error {
   354  	if statistics == nil {
   355  		return xerrors.WithStackTrace(errWriteResultResponseStatisticIsNil)
   356  	}
   357  
   358  	s.PersistingTime = statistics.GetPersistingTime().AsDuration()
   359  	s.MinQueueWaitTime = statistics.GetMinQueueWaitTime().AsDuration()
   360  	s.MaxQueueWaitTime = statistics.GetMaxQueueWaitTime().AsDuration()
   361  	s.TopicQuotaWaitTime = statistics.GetTopicQuotaWaitTime().AsDuration()
   362  
   363  	return nil
   364  }
   365  
   366  type UpdateTokenRequest struct {
   367  	clientMessageImpl
   368  
   369  	rawtopiccommon.UpdateTokenRequest
   370  }
   371  
   372  type UpdateTokenResponse struct {
   373  	rawtopiccommon.UpdateTokenResponse
   374  
   375  	serverMessageImpl
   376  
   377  	rawtopiccommon.ServerMessageMetadata
   378  }