12
12
// See the License for the specific language governing permissions and
13
13
// limitations under the License.
14
14
15
+ import memoizeOne from 'memoize-one' ;
15
16
import * as _ from 'lodash' ;
16
17
import DRange from 'drange' ;
17
18
import { Trace , Span } from '../../../types/trace' ;
@@ -21,23 +22,25 @@ import colorGenerator from '../../../utils/color-generator';
21
22
const serviceName = 'Service Name' ;
22
23
const operationName = 'Operation Name' ;
23
24
24
- let parentChildOfMap : Record < string , Span [ ] > ;
25
+ function parentChildOfMap ( allSpans : Span [ ] ) : Record < string , Span [ ] > {
26
+ let parentChildOfMap = { } ;
27
+ allSpans . forEach ( s => {
28
+ if ( s . references ) {
29
+ // Filter for CHILD_OF we don't want to calculate FOLLOWS_FROM (prod-cons)
30
+ const parentIDs = s . references . filter ( r => r . refType === 'CHILD_OF' ) . map ( r => r . spanID ) ;
31
+ parentIDs . forEach ( ( pID : string ) => {
32
+ parentChildOfMap [ pID ] = parentChildOfMap [ pID ] || [ ] ;
33
+ parentChildOfMap [ pID ] . push ( s ) ;
34
+ } ) ;
35
+ }
36
+ } ) ;
37
+ return parentChildOfMap ;
38
+ }
39
+
40
+ const memoizedParentChildOfMap = memoizeOne ( parentChildOfMap ) ;
25
41
26
42
function getChildOfSpans ( parentID : string , allSpans : Span [ ] ) : Span [ ] {
27
- if ( ! parentChildOfMap ) {
28
- parentChildOfMap = { } ;
29
- allSpans . forEach ( s => {
30
- if ( s . references ) {
31
- // Filter for CHILD_OF we don't want to calculate FOLLOWS_FROM (prod-cons)
32
- const parentIDs = s . references . filter ( r => r . refType === 'CHILD_OF' ) . map ( r => r . spanID ) ;
33
- parentIDs . forEach ( ( pID : string ) => {
34
- parentChildOfMap [ pID ] = parentChildOfMap [ pID ] || [ ] ;
35
- parentChildOfMap [ pID ] . push ( s ) ;
36
- } ) ;
37
- }
38
- } ) ;
39
- }
40
- return parentChildOfMap [ parentID ] || [ ] ;
43
+ return memoizedParentChildOfMap ( allSpans ) [ parentID ] || [ ] ;
41
44
}
42
45
43
46
function getChildOfDrange ( parentID : string , allSpans : Span [ ] ) {
@@ -50,10 +53,20 @@ function getChildOfDrange(parentID: string, allSpans: Span[]) {
50
53
}
51
54
52
55
function computeSelfTime ( span : Span , allSpans : Span [ ] ) : number {
53
- const cdr = new DRange ( span . startTime , span . startTime + span . duration - 1 ) . intersect (
56
+ // We want to represent spans as half-open intervals like [startTime, startTime + duration).
57
+ // This way the subtraction preserves the right boundaries. However, DRange treats all
58
+ // intervals as inclusive. For example,
59
+ // range(1, 10).subtract(4, 8) => range([1, 3], [9-10])
60
+ // length=(3-1)+(10-9)=2+1=3
61
+ // In other words, we took an interval of length=10-1=9 and subtracted length=8-4=4.
62
+ // We should've ended up with length 9-4=5, but we got 3.
63
+ // To work around that, we multiply start/end times by 10 and subtract one from the end.
64
+ // So instead of [1-10] we get [10-99]. This makes the intervals work like half-open.
65
+ if ( ! span . hasChildren ) return span . duration ;
66
+ const spanRange = new DRange ( span . startTime , span . startTime + span . duration - 1 ) . subtract (
54
67
getChildOfDrange ( span . spanID , allSpans )
55
68
) ;
56
- return span . duration - cdr . length ;
69
+ return spanRange . length ;
57
70
}
58
71
59
72
function computeColumnValues ( trace : Trace , span : Span , allSpans : Span [ ] , resultValue : any ) {
@@ -107,7 +120,6 @@ function valueFirstDropdown(selectedTagKey: string, trace: Trace) {
107
120
let color = '' ;
108
121
let allDiffColumnValues = [ ] ;
109
122
const allSpans = trace . spans ;
110
- parentChildOfMap = null ;
111
123
// all possibilities that can be displayed
112
124
if ( selectedTagKey === serviceName ) {
113
125
const temp = _ . chain ( allSpans )
@@ -271,7 +283,6 @@ function buildDetail(
271
283
isDetail : boolean ,
272
284
trace : Trace
273
285
) {
274
- parentChildOfMap = null ;
275
286
const newColumnValues = [ ] ;
276
287
for ( let j = 0 ; j < diffNamesA . length ; j ++ ) {
277
288
let color = '' ;
@@ -337,7 +348,6 @@ function buildDetail(
337
348
function generateDetailRest ( allColumnValues : ITableSpan [ ] , selectedTagKeySecond : string , trace : Trace ) {
338
349
const allSpans = trace . spans ;
339
350
const newTable = [ ] ;
340
- parentChildOfMap = null ;
341
351
for ( let i = 0 ; i < allColumnValues . length ; i ++ ) {
342
352
newTable . push ( allColumnValues [ i ] ) ;
343
353
if ( ! allColumnValues [ i ] . isDetail ) {
0 commit comments