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 }