@@ -34,9 +34,9 @@ type payloadV1 struct {
34
34
// the 0th position in the stringTable should always be the empty string.
35
35
strings * stringTable
36
36
37
- // Bitmap to track which index fields are set (bits 1-11 for field IDs 1-11)
37
+ // fieldSet tracks which index fields are set (bits 1-11 for field IDs 1-11)
38
38
// Bit 0 is unused since field IDs start from 1
39
- fieldSet uint16
39
+ fieldSet bitmap
40
40
41
41
// Array to store the actual index values for set fields
42
42
// Index in array corresponds to field ID (fieldValues[1] = containerID value, etc.)
@@ -190,21 +190,24 @@ func (p *payloadV1) Read(b []byte) (int, error) {
190
190
}
191
191
192
192
func (p * payloadV1 ) encode () {
193
- p .buf = encodeField (p .buf , 1 , p .strings )
193
+ // fieldEncoded tracks which index fields have been encoded (bits 1-11 for field IDs 1-11)
194
+ // Bit 0 is unused since field IDs start from 1.
195
+ var fieldEncoded bitmap
196
+
194
197
for i := uint32 (2 ); i <= 9 ; i ++ {
195
- if ! p .isFieldSet (i ) {
198
+ if ! p .hasIndexField (i ) {
199
+ continue
200
+ }
201
+ if fieldEncoded .Has (i ) {
202
+ p .buf = encodeField (p .buf , i , p .getIndexField (i ))
196
203
continue
197
204
}
198
- p .buf = encodeField (p .buf , i , p .getIndexField (i ))
205
+ v := encodableString (p .getStringField (i ))
206
+ p .buf = encodeField (p .buf , i , & v )
207
+ fieldEncoded .Set (i )
199
208
}
200
209
}
201
210
202
- func encodeField [T encodeDecoder ](buf []byte , ref uint32 , w T ) []byte {
203
- buf = msgp .AppendUint32 (buf , ref )
204
- buf = w .encode (buf )
205
- return buf
206
- }
207
-
208
211
// Write implements io.Writer. It writes data directly to the internal buffers.
209
212
func (p * payloadV1 ) Write (data []byte ) (int , error ) {
210
213
p .buf = append (p .buf , data ... )
@@ -227,7 +230,7 @@ func (p *payloadV1) hydrate() ([]byte, error) {
227
230
break
228
231
}
229
232
switch field {
230
- case 1 : // strings
233
+ case 1 : // strings - unused because we are using an embedded streaming string table
231
234
o , err = p .strings .decode (o )
232
235
case 2 : // containerID
233
236
fallthrough
@@ -244,12 +247,25 @@ func (p *payloadV1) hydrate() ([]byte, error) {
244
247
case 8 : // hostname
245
248
fallthrough
246
249
case 9 : // appVersion
247
- var idx index
248
- o , err = idx .decode (o )
249
- if err != nil {
250
- break
250
+ switch detectStringOrUint32Format (o [0 ]) {
251
+ case 0 : // string
252
+ var v encodableString
253
+ o , err = v .decode (o )
254
+ if err != nil {
255
+ break
256
+ }
257
+ idx := p .strings .Add (string (v ))
258
+ p .setIndexField (field , idx )
259
+ case 1 : // string
260
+ var idx index
261
+ o , err = idx .decode (o )
262
+ if err != nil {
263
+ break
264
+ }
265
+ p .setIndexField (field , idx )
266
+ default :
267
+ err = fmt .Errorf ("invalid type on field %d" , field )
251
268
}
252
- p .setIndexField (field , idx )
253
269
case 10 , 11 :
254
270
// TODO: implement remaining fields
255
271
default :
@@ -268,32 +284,12 @@ func (p *payloadV1) Close() error {
268
284
return nil
269
285
}
270
286
271
- type encodeDecoder interface {
272
- encode ([]byte ) []byte
273
- decode ([]byte ) ([]byte , error )
274
- }
275
-
276
- type index uint32
277
-
278
- func (i index ) encode (buf []byte ) []byte {
279
- return msgp .AppendUint32 (buf , uint32 (i ))
280
- }
281
-
282
- func (i * index ) decode (buf []byte ) ([]byte , error ) {
283
- v , o , err := msgp .ReadUint32Bytes (buf )
284
- if err != nil {
285
- return o , err
286
- }
287
- * i = index (v )
288
- return o , nil
289
- }
290
-
291
287
// getIndexField returns the index value for the given field ID if it's set, nil otherwise
292
288
func (p * payloadV1 ) getIndexField (fieldID uint32 ) * index {
293
289
if fieldID == 0 || fieldID >= 12 {
294
290
return nil
295
291
}
296
- if p .fieldSet & ( 1 << fieldID ) != 0 {
292
+ if p .fieldSet . Has ( fieldID ) {
297
293
return & p .fieldValues [fieldID ]
298
294
}
299
295
return nil
@@ -305,24 +301,24 @@ func (p *payloadV1) setIndexField(fieldID uint32, value index) {
305
301
return
306
302
}
307
303
p .fieldValues [fieldID ] = value
308
- p .fieldSet |= ( 1 << fieldID )
304
+ p .fieldSet . Set ( fieldID )
309
305
p .fields ++
310
306
}
311
307
312
- // isFieldSet checks if a field is set using bitwise operations
313
- func (p * payloadV1 ) isFieldSet (fieldID uint32 ) bool {
308
+ // hasIndexField checks if a field is set using bitwise operations
309
+ func (p * payloadV1 ) hasIndexField (fieldID uint32 ) bool {
314
310
if fieldID == 0 || fieldID >= 12 {
315
311
return false
316
312
}
317
- return p .fieldSet & ( 1 << fieldID ) != 0
313
+ return p .fieldSet . Has ( fieldID )
318
314
}
319
315
320
316
// getStringField returns the string value for the given field ID by looking up the index in the string table
321
317
func (p * payloadV1 ) getStringField (fieldID uint32 ) string {
322
318
if fieldID == 0 || fieldID >= 12 {
323
319
return ""
324
320
}
325
- if p .fieldSet & ( 1 << fieldID ) == 0 {
321
+ if ! p .fieldSet . Has ( fieldID ) {
326
322
return ""
327
323
}
328
324
idx := p .fieldValues [fieldID ]
@@ -382,12 +378,108 @@ func (p *payloadV1) SetAppVersion(value string) {
382
378
p .setIndexField (9 , idx )
383
379
}
384
380
381
+ func encodeField [T encodeDecoder ](buf []byte , ref uint32 , w T ) []byte {
382
+ buf = msgp .AppendUint32 (buf , ref )
383
+ buf = w .encode (buf )
384
+ return buf
385
+ }
386
+
387
+ // detectStringOrUint32Format examines the first byte of MessagePack data
388
+ // to determine if it represents a string or uint32 format.
389
+ // Returns 0 if string, 1 if uint32, or -1 if invalid.
390
+ func detectStringOrUint32Format (firstByte byte ) int8 {
391
+ switch firstByte {
392
+ // String formats
393
+ case 0xd9 , 0xda , 0xdb : // str8, str16, str32
394
+ return 0
395
+ case 0xce : // uint32
396
+ return 1
397
+ default :
398
+ // Check for fixstr: high 3 bits should be 0b101 (0xa0)
399
+ if firstByte & 0xe0 == 0xa0 {
400
+ return 0
401
+ }
402
+ // Check for positive fixint: high bit should be 0 (values 0-127)
403
+ if firstByte & 0x80 == 0 {
404
+ return 1
405
+ }
406
+ return - 1
407
+ }
408
+ }
409
+
410
+ type encodableString string
411
+
412
+ func (es encodableString ) encode (buf []byte ) []byte {
413
+ return msgp .AppendString (buf , string (es ))
414
+ }
415
+
416
+ func (es * encodableString ) decode (buf []byte ) ([]byte , error ) {
417
+ v , o , err := msgp .ReadStringBytes (buf )
418
+ if err != nil {
419
+ return o , err
420
+ }
421
+ * es = encodableString (v )
422
+ return o , nil
423
+ }
424
+
425
+ type encodeDecoder interface {
426
+ encode ([]byte ) []byte
427
+ decode ([]byte ) ([]byte , error )
428
+ }
429
+
430
+ type index uint32
431
+
432
+ func (i index ) encode (buf []byte ) []byte {
433
+ return msgp .AppendUint32 (buf , uint32 (i ))
434
+ }
435
+
436
+ func (i * index ) decode (buf []byte ) ([]byte , error ) {
437
+ v , o , err := msgp .ReadUint32Bytes (buf )
438
+ if err != nil {
439
+ return o , err
440
+ }
441
+ * i = index (v )
442
+ return o , nil
443
+ }
444
+
445
+ type bitmap uint16
446
+
447
+ func (bm * bitmap ) Set (i uint32 ) {
448
+ * bm |= (1 << i )
449
+ }
450
+
451
+ func (bm bitmap ) Has (i uint32 ) bool {
452
+ return bm & (1 << i ) != 0
453
+ }
454
+
385
455
type stringTable struct {
386
456
strings []string // list of strings
387
457
indices map [unique.Handle [string ]]index // map strings to their indices
388
458
nextIndex index // last index of the stringTable
389
459
}
390
460
461
+ func newStringTable () * stringTable {
462
+ return & stringTable {
463
+ strings : []string {"" },
464
+ indices : map [unique.Handle [string ]]index {
465
+ unique .Make ("" ): 0 ,
466
+ },
467
+ nextIndex : 1 ,
468
+ }
469
+ }
470
+
471
+ func (s * stringTable ) Add (str string ) index {
472
+ k := unique .Make (str )
473
+ if v , ok := s .indices [k ]; ok {
474
+ return v
475
+ }
476
+ v := s .nextIndex
477
+ s .indices [k ] = v
478
+ s .strings = append (s .strings , str )
479
+ s .nextIndex += 1
480
+ return v
481
+ }
482
+
391
483
func (st * stringTable ) encode (buf []byte ) []byte {
392
484
o := msgp .AppendArrayHeader (buf , uint32 (len (st .strings )))
393
485
for ix := range st .strings {
@@ -439,44 +531,15 @@ const (
439
531
keyValueListType // []keyValue -- 7
440
532
)
441
533
442
- // keys in a keyValue can either be a string or a uint32 index
443
- // isString is true when the key is a string value, and false when the key is a uint32 index
444
- type streamingKey struct {
445
- isString bool
446
- stringValue string
447
- }
448
-
449
534
// keyValue is made up of the key and an AnyValue (the type of the value and the value itself)
450
535
// The key is either a uint32 index into the string table or a string value.
451
536
type keyValue struct {
452
- key streamingKey
537
+ key encodableString
453
538
value anyValue
454
539
}
455
540
456
541
type keyValueList []keyValue
457
542
458
- func newStringTable () * stringTable {
459
- return & stringTable {
460
- strings : []string {"" },
461
- indices : map [unique.Handle [string ]]index {
462
- unique .Make ("" ): 0 ,
463
- },
464
- nextIndex : 1 ,
465
- }
466
- }
467
-
468
- func (s * stringTable ) Add (str string ) index {
469
- k := unique .Make (str )
470
- if v , ok := s .indices [k ]; ok {
471
- return v
472
- }
473
- v := s .nextIndex
474
- s .indices [k ] = v
475
- s .strings = append (s .strings , str )
476
- s .nextIndex += 1
477
- return v
478
- }
479
-
480
543
// traceChunk represents a list of spans with the same trace ID,
481
544
// i.e. a chunk of a trace
482
545
type traceChunk struct {
0 commit comments