@@ -107,8 +107,8 @@ pub mod linux {
107107 }
108108 }
109109
110- // We maintain the convention in libdatadog that the `root_span_id ` attribute key is always the
111- // very first in the string table, so its key index is guaranteed to be zero.
110+ // We maintain the convention in libdatadog that the `local_root_span_id ` attribute key is
111+ // always the very first in the string table, so its key index is guaranteed to be zero.
112112 const ROOT_SPAN_KEY_INDEX : u8 = 0 ;
113113
114114 /// Maximum size in bytes of the `attrs_data` field.
@@ -169,13 +169,13 @@ pub mod linux {
169169 }
170170
171171 impl ThreadContextRecord {
172- /// Build a record with the given trace id, span id and attributes. The `root_span_id` is a
173- /// distinguished attribute with special handling for convenience, but it ends up as other
174- /// attributes in `attrs_data`.
172+ /// Build a record with the given trace id, span id and attributes. The
173+ /// `local_root_span_id` is a distinguished attribute with special handling for
174+ /// convenience, but it ends up as other attributes in `attrs_data`.
175175 fn new (
176176 trace_id : [ u8 ; 16 ] ,
177177 span_id : [ u8 ; 8 ] ,
178- root_span_id : & str ,
178+ local_root_span_id : [ u8 ; 8 ] ,
179179 attrs : & [ ( u8 , & str ) ] ,
180180 ) -> Self {
181181 const { assert ! ( size_of:: <ThreadContextRecord >( ) == 640 ) }
@@ -185,7 +185,7 @@ pub mod linux {
185185 span_id,
186186 ..Default :: default ( )
187187 } ;
188- record. set_attrs ( root_span_id , attrs) ;
188+ record. set_attrs ( local_root_span_id , attrs) ;
189189 record
190190 }
191191
@@ -210,13 +210,15 @@ pub mod linux {
210210 /// recovery would require us to be able to rollback to the previous attributes which would
211211 /// hurt the happy path, or leave the record in a inconsistent state. Another possibility
212212 /// would be to error out and reset the record in that situation.
213- fn set_attrs ( & mut self , root_span_id : & str , attributes : & [ ( u8 , & str ) ] ) -> bool {
214- let mut offset = 0 ;
213+ fn set_attrs ( & mut self , local_root_span_id : [ u8 ; 8 ] , attributes : & [ ( u8 , & str ) ] ) -> bool {
215214 let mut fully_encoded = true ;
216- let root_span_attr = ( ROOT_SPAN_KEY_INDEX , root_span_id) ;
217- let full_attrs = std:: iter:: once ( & root_span_attr) . chain ( attributes) ;
218215
219- for & ( key_index, val) in full_attrs {
216+ self . attrs_data [ 0 ] = ROOT_SPAN_KEY_INDEX ;
217+ self . attrs_data [ 1 ] = 8 ;
218+ self . attrs_data [ 2 ..10 ] . copy_from_slice ( local_root_span_id. as_slice ( ) ) ;
219+ let mut offset = 10 ;
220+
221+ for & ( key_index, val) in attributes {
220222 let val_bytes = val. as_bytes ( ) ;
221223 let val_len = val_bytes. len ( ) ;
222224 let val_len = if val_len > 255 {
@@ -277,13 +279,13 @@ pub mod linux {
277279 pub fn new (
278280 trace_id : [ u8 ; 16 ] ,
279281 span_id : [ u8 ; 8 ] ,
280- root_span_id : & str ,
282+ local_root_span_id : [ u8 ; 8 ] ,
281283 attrs : & [ ( u8 , & str ) ] ,
282284 ) -> Self {
283285 Self :: from ( ThreadContextRecord :: new (
284286 trace_id,
285287 span_id,
286- root_span_id ,
288+ local_root_span_id ,
287289 attrs,
288290 ) )
289291 }
@@ -361,7 +363,7 @@ pub mod linux {
361363 pub fn update (
362364 trace_id : [ u8 ; 16 ] ,
363365 span_id : [ u8 ; 8 ] ,
364- root_span_id : & str ,
366+ local_root_span_id : [ u8 ; 8 ] ,
365367 attrs : & [ ( u8 , & str ) ] ,
366368 ) {
367369 let slot = get_tls_slot ( ) ;
@@ -372,7 +374,7 @@ pub mod linux {
372374
373375 current. trace_id = trace_id;
374376 current. span_id = span_id;
375- current. set_attrs ( root_span_id , attrs) ;
377+ current. set_attrs ( local_root_span_id , attrs) ;
376378
377379 compiler_fence ( Ordering :: SeqCst ) ;
378380 current. valid . store ( 1 , Ordering :: Relaxed ) ;
@@ -382,7 +384,7 @@ pub mod linux {
382384 // `ThreadContext::new` already initialises `valid = 1`.
383385 let _ = Self :: swap (
384386 slot,
385- ThreadContext :: new ( trace_id, span_id, root_span_id , attrs) . into_raw ( ) ,
387+ ThreadContext :: new ( trace_id, span_id, local_root_span_id , attrs) . into_raw ( ) ,
386388 ) ;
387389 }
388390 }
@@ -422,12 +424,13 @@ pub mod linux {
422424 fn tls_lifecycle_basic ( ) {
423425 let trace_id = [ 1u8 ; 16 ] ;
424426 let span_id = [ 2u8 ; 8 ] ;
427+ let root_span_id = [ 3u8 ; 8 ] ;
425428
426429 assert ! (
427430 read_tls_context_ptr( ) . is_null( ) ,
428431 "TLS must be null initially"
429432 ) ;
430- ThreadContext :: new ( trace_id, span_id, "" , & [ ] ) . attach ( ) ;
433+ ThreadContext :: new ( trace_id, span_id, root_span_id , & [ ] ) . attach ( ) ;
431434 assert ! (
432435 !read_tls_context_ptr( ) . is_null( ) ,
433436 "TLS must not be null after attach"
@@ -457,8 +460,9 @@ pub mod linux {
457460 fn raw_tls_pointer_read ( ) {
458461 let trace_id = [ 1u8 ; 16 ] ;
459462 let span_id = [ 2u8 ; 8 ] ;
463+ let root_span_id = [ 3u8 ; 8 ] ;
460464
461- ThreadContext :: new ( trace_id, span_id, "" , & [ ] ) . attach ( ) ;
465+ ThreadContext :: new ( trace_id, span_id, root_span_id , & [ ] ) . attach ( ) ;
462466
463467 let ptr = read_tls_context_ptr ( ) ;
464468 assert ! ( !ptr. is_null( ) , "TLS must be non-null after attach" ) ;
@@ -468,32 +472,34 @@ pub mod linux {
468472 assert_eq ! ( record. trace_id, trace_id) ;
469473 assert_eq ! ( record. span_id, span_id) ;
470474 assert_eq ! ( record. valid. load( Ordering :: Relaxed ) , 1 ) ;
471- assert_eq ! ( record. attrs_data_size, 2 ) ;
475+ // 1 (key) + 1 (len) + 8 (root_span_id bytes) = 10
476+ assert_eq ! ( record. attrs_data_size, 10 ) ;
472477
473478 let _ = ThreadContext :: detach ( ) ;
474479 }
475480
476481 #[ test]
477482 #[ cfg_attr( miri, ignore) ]
478483 fn attribute_encoding_basic ( ) {
479- let root_span_id = "aaaa-bbbb" ;
484+ let root_span_id = [ 0u8 ; 8 ] ;
480485 let attrs: & [ ( u8 , & str ) ] = & [ ( 1 , "GET" ) , ( 2 , "/api/v1" ) ] ;
481486 ThreadContext :: new ( [ 0u8 ; 16 ] , [ 0u8 ; 8 ] , root_span_id, attrs) . attach ( ) ;
482487
483488 let ptr = read_tls_context_ptr ( ) ;
484489 assert ! ( !ptr. is_null( ) ) ;
485490 let record = unsafe { & * ptr } ;
486- let expected_size: u16 = ( 2 + 9 + 2 + 3 + 2 + 7 ) as u16 ;
491+ // 1+1+8 (root_span_id) + 1+1+3 (GET) + 1+1+7 (/api/v1)
492+ let expected_size: u16 = ( 2 + 8 + 2 + 3 + 2 + 7 ) as u16 ;
487493 assert_eq ! ( record. attrs_data_size, expected_size) ;
488494 assert_eq ! ( record. attrs_data[ 0 ] , 0 ) ;
489- assert_eq ! ( record. attrs_data[ 1 ] , 9 ) ;
490- assert_eq ! ( & record. attrs_data[ 2 ..11 ] , b"aaaa-bbbb" ) ;
491- assert_eq ! ( record. attrs_data[ 11 ] , 1 ) ;
492- assert_eq ! ( record. attrs_data[ 12 ] , 3 ) ;
493- assert_eq ! ( & record. attrs_data[ 13 .. 16 ] , b"GET" ) ;
494- assert_eq ! ( record. attrs_data[ 16 ] , 2 ) ;
495- assert_eq ! ( record. attrs_data[ 17 ] , 7 ) ;
496- assert_eq ! ( & record. attrs_data[ 18 .. 25 ] , b"/api/v1" ) ;
495+ assert_eq ! ( record. attrs_data[ 1 ] , 8 ) ;
496+ assert_eq ! ( & record. attrs_data[ 2 ..10 ] , & root_span_id ) ;
497+ assert_eq ! ( record. attrs_data[ 10 ] , 1 ) ;
498+ assert_eq ! ( record. attrs_data[ 11 ] , 3 ) ;
499+ assert_eq ! ( & record. attrs_data[ 12 .. 15 ] , b"GET" ) ;
500+ assert_eq ! ( record. attrs_data[ 15 ] , 2 ) ;
501+ assert_eq ! ( record. attrs_data[ 16 ] , 7 ) ;
502+ assert_eq ! ( & record. attrs_data[ 17 .. 24 ] , b"/api/v1" ) ;
497503
498504 let _ = ThreadContext :: detach ( ) ;
499505 }
@@ -503,30 +509,31 @@ pub mod linux {
503509 fn attribute_truncation_on_overflow ( ) {
504510 // Build attributes whose combined encoded size exceeds MAX_ATTRS_DATA_SIZE.
505511 // Each max entry: 1 (key) + 1 (len) + 255 (val) = 257 bytes.
506- // Two such entries: 514 bytes, plus an empty root_span_id: 516.
507- // A third entry of 100 chars would need 102 bytes, bringing the total to 618 > 612, so
512+ // root_span_id: 1 (key) + 1 (len) + 8 (val) = 10 bytes.
513+ // Two such entries: 514 bytes, plus root_span_id: 524.
514+ // A third entry of 100 chars would need 102 bytes, bringing the total to 626 > 612, so
508515 // the third entry must be dropped.
509516 let val_a = "a" . repeat ( 255 ) ; // 257 bytes encoded
510517 let val_b = "b" . repeat ( 255 ) ; // 257 bytes encoded → 514 total
511- let val_c = "c" . repeat ( 100 ) ; // 102 bytes encoded → 616 total: must be dropped
518+ let val_c = "c" . repeat ( 100 ) ; // 102 bytes encoded → 626 total: must be dropped
512519
513520 let attrs: & [ ( u8 , & str ) ] = & [
514521 ( 1 , val_a. as_str ( ) ) ,
515522 ( 2 , val_b. as_str ( ) ) ,
516523 ( 3 , val_c. as_str ( ) ) ,
517524 ] ;
518525
519- ThreadContext :: new ( [ 0u8 ; 16 ] , [ 0u8 ; 8 ] , "" , attrs) . attach ( ) ;
526+ ThreadContext :: new ( [ 0u8 ; 16 ] , [ 0u8 ; 8 ] , [ 0u8 ; 8 ] , attrs) . attach ( ) ;
520527
521528 let ptr = read_tls_context_ptr ( ) ;
522529 assert ! ( !ptr. is_null( ) ) ;
523530 let record = unsafe { & * ptr } ;
524- // Only the first two entries fit (514 bytes + 2 bytes for empty root span id ).
525- assert_eq ! ( record. attrs_data_size, 516 ) ;
526- assert_eq ! ( record. attrs_data[ 2 ] , 1 ) ;
527- assert_eq ! ( record. attrs_data[ 3 ] , 255 ) ;
528- assert_eq ! ( record. attrs_data[ 259 ] , 2 ) ;
529- assert_eq ! ( record. attrs_data[ 260 ] , 255 ) ;
531+ // Only the first two entries fit (514 bytes + 10 bytes for root_span_id ).
532+ assert_eq ! ( record. attrs_data_size, 524 ) ;
533+ assert_eq ! ( record. attrs_data[ 10 ] , 1 ) ;
534+ assert_eq ! ( record. attrs_data[ 11 ] , 255 ) ;
535+ assert_eq ! ( record. attrs_data[ 267 ] , 2 ) ;
536+ assert_eq ! ( record. attrs_data[ 268 ] , 255 ) ;
530537
531538 let _ = ThreadContext :: detach ( ) ;
532539 }
@@ -536,10 +543,10 @@ pub mod linux {
536543 fn update_record_in_place ( ) {
537544 let trace_id1 = [ 1u8 ; 16 ] ;
538545 let span_id1 = [ 1u8 ; 8 ] ;
539- let root_span_id1 = "xxxx" ;
546+ let root_span_id1 = [ 0x78u8 ; 8 ] ;
540547 let trace_id2 = [ 2u8 ; 16 ] ;
541548 let span_id2 = [ 2u8 ; 8 ] ;
542- let root_span_id2 = "yyyy" ;
549+ let root_span_id2 = [ 0x79u8 ; 8 ] ;
543550
544551 // Updating before any context is attached should be equivalent to `attach()`
545552 ThreadContext :: update ( trace_id1, span_id1, root_span_id1, & [ ( 0 , "v1" ) ] ) ;
@@ -551,11 +558,11 @@ pub mod linux {
551558 assert_eq ! ( record. span_id, span_id1) ;
552559 assert_eq ! ( record. valid. load( Ordering :: Relaxed ) , 1 ) ;
553560 assert_eq ! ( record. attrs_data[ 0 ] , 0 ) ;
554- assert_eq ! ( record. attrs_data[ 1 ] , 4 ) ;
555- assert_eq ! ( & record. attrs_data[ 2 ..6 ] , root_span_id1. as_bytes ( ) ) ;
556- assert_eq ! ( record. attrs_data[ 6 ] , 0 ) ;
557- assert_eq ! ( record. attrs_data[ 7 ] , 2 ) ;
558- assert_eq ! ( & record. attrs_data[ 8 .. 10 ] , b"v1" ) ;
561+ assert_eq ! ( record. attrs_data[ 1 ] , 8 ) ;
562+ assert_eq ! ( & record. attrs_data[ 2 ..10 ] , & root_span_id1) ;
563+ assert_eq ! ( record. attrs_data[ 10 ] , 0 ) ;
564+ assert_eq ! ( record. attrs_data[ 11 ] , 2 ) ;
565+ assert_eq ! ( & record. attrs_data[ 12 .. 14 ] , b"v1" ) ;
559566
560567 ThreadContext :: update ( trace_id2, span_id2, root_span_id2, & [ ( 0 , "v2" ) ] ) ;
561568
@@ -570,11 +577,11 @@ pub mod linux {
570577 assert_eq ! ( record. span_id, span_id2) ;
571578 assert_eq ! ( record. valid. load( Ordering :: Relaxed ) , 1 ) ;
572579 assert_eq ! ( record. attrs_data[ 0 ] , 0 ) ;
573- assert_eq ! ( record. attrs_data[ 1 ] , 4 ) ;
574- assert_eq ! ( & record. attrs_data[ 2 ..6 ] , root_span_id2. as_bytes ( ) ) ;
575- assert_eq ! ( record. attrs_data[ 6 ] , 0 ) ;
576- assert_eq ! ( record. attrs_data[ 7 ] , 2 ) ;
577- assert_eq ! ( & record. attrs_data[ 8 .. 10 ] , b"v2" ) ;
580+ assert_eq ! ( record. attrs_data[ 1 ] , 8 ) ;
581+ assert_eq ! ( & record. attrs_data[ 2 ..10 ] , & root_span_id2) ;
582+ assert_eq ! ( record. attrs_data[ 10 ] , 0 ) ;
583+ assert_eq ! ( record. attrs_data[ 11 ] , 2 ) ;
584+ assert_eq ! ( & record. attrs_data[ 12 .. 14 ] , b"v2" ) ;
578585
579586 let _ = ThreadContext :: detach ( ) ;
580587 assert ! ( read_tls_context_ptr( ) . is_null( ) ) ;
@@ -583,7 +590,7 @@ pub mod linux {
583590 #[ test]
584591 #[ cfg_attr( miri, ignore) ]
585592 fn explicit_detach_nulls_tls ( ) {
586- ThreadContext :: new ( [ 3u8 ; 16 ] , [ 3u8 ; 8 ] , "aaaa" , & [ ] ) . attach ( ) ;
593+ ThreadContext :: new ( [ 0u8 ; 16 ] , [ 0u8 ; 8 ] , [ 0u8 ; 8 ] , & [ ] ) . attach ( ) ;
587594 assert ! ( !read_tls_context_ptr( ) . is_null( ) ) ;
588595
589596 let _ = ThreadContext :: detach ( ) ;
@@ -598,14 +605,16 @@ pub mod linux {
598605 #[ cfg_attr( miri, ignore) ]
599606 fn long_value_capped_at_255_bytes ( ) {
600607 let long_val = "a" . repeat ( 300 ) ;
601- ThreadContext :: new ( [ 0u8 ; 16 ] , [ 0u8 ; 8 ] , "bbbb" , & [ ( 0 , long_val. as_str ( ) ) ] ) . attach ( ) ;
608+ ThreadContext :: new ( [ 0u8 ; 16 ] , [ 0u8 ; 8 ] , [ 0u8 ; 8 ] , & [ ( 0 , long_val. as_str ( ) ) ] ) . attach ( ) ;
602609
603610 let ptr = read_tls_context_ptr ( ) ;
604611 assert ! ( !ptr. is_null( ) ) ;
605612 let record = unsafe { & * ptr } ;
606- let val_len = record. attrs_data [ 2 + 4 + 1 ] ;
613+ // root_span_id occupies offset 0..10, then the attr entry starts at 10: key at [10],
614+ // len at [11]
615+ let val_len = record. attrs_data [ 2 + 8 + 1 ] ;
607616 assert_eq ! ( val_len, 255 , "value must be capped at 255 bytes" ) ;
608- assert_eq ! ( record. attrs_data_size, 2 + 4 + 2 + 255 ) ;
617+ assert_eq ! ( record. attrs_data_size, 2 + 8 + 2 + 255 ) ;
609618
610619 let _ = ThreadContext :: detach ( ) ;
611620 }
@@ -621,10 +630,10 @@ pub mod linux {
621630
622631 let spawned_trace_id = [ 0xABu8 ; 16 ] ;
623632 let spawned_span_id = [ 0xCDu8 ; 8 ] ;
624- let spawned_root_span_id = "xxxx" ;
633+ let spawned_root_span_id = [ 0xEFu8 ; 8 ] ;
625634 let main_trace_id = [ 0x11u8 ; 16 ] ;
626635 let main_span_id = [ 0x22u8 ; 8 ] ;
627- let main_root_span_id = "yyyy" ;
636+ let main_root_span_id = [ 0x33u8 ; 8 ] ;
628637
629638 let handle = std:: thread:: spawn ( move || {
630639 ThreadContext :: new ( spawned_trace_id, spawned_span_id, spawned_root_span_id, & [ ] )
@@ -641,10 +650,7 @@ pub mod linux {
641650 let record = unsafe { & * ptr } ;
642651 assert_eq ! ( record. trace_id, spawned_trace_id) ;
643652 assert_eq ! ( record. span_id, spawned_span_id) ;
644- assert_eq ! (
645- & record. attrs_data[ 2 ..( record. attrs_data_size as usize ) ] ,
646- spawned_root_span_id. as_bytes( )
647- ) ;
653+ assert_eq ! ( & record. attrs_data[ 2 ..10 ] , & spawned_root_span_id) ;
648654
649655 let _ = ThreadContext :: detach ( ) ;
650656 assert ! ( read_tls_context_ptr( ) . is_null( ) ) ;
@@ -665,10 +671,7 @@ pub mod linux {
665671 let record = unsafe { & * ptr } ;
666672 assert_eq ! ( record. trace_id, main_trace_id) ;
667673 assert_eq ! ( record. span_id, main_span_id) ;
668- assert_eq ! (
669- & record. attrs_data[ 2 ..( record. attrs_data_size as usize ) ] ,
670- main_root_span_id. as_bytes( )
671- ) ;
674+ assert_eq ! ( & record. attrs_data[ 2 ..10 ] , & main_root_span_id) ;
672675
673676 barrier. wait ( ) ;
674677
0 commit comments