44 * you may not use this file except in compliance with the Elastic License.
55 */
66
7- import { uniquePidForProcess , uniqueParentPidForProcess } from '../process_event' ;
8- import { IndexedProcessTree , AdjacentProcessMap } from '../../types' ;
7+ import { uniquePidForProcess , uniqueParentPidForProcess , orderByTime } from '../process_event' ;
8+ import { IndexedProcessTree } from '../../types' ;
99import { ResolverEvent } from '../../../../common/endpoint/types' ;
1010import { levelOrder as baseLevelOrder } from '../../lib/tree_sequencers' ;
1111
1212/**
13- * Create a new IndexedProcessTree from an array of ProcessEvents
13+ * Create a new IndexedProcessTree from an array of ProcessEvents.
14+ * siblings will be ordered by timestamp
1415 */
15- export function factory ( processes : ResolverEvent [ ] ) : IndexedProcessTree {
16+ export function factory (
17+ // Array of processes to index as a tree
18+ processes : ResolverEvent [ ]
19+ ) : IndexedProcessTree {
1620 const idToChildren = new Map < string | undefined , ResolverEvent [ ] > ( ) ;
1721 const idToValue = new Map < string , ResolverEvent > ( ) ;
18- const idToAdjacent = new Map < string , AdjacentProcessMap > ( ) ;
19-
20- function emptyAdjacencyMap ( id : string ) : AdjacentProcessMap {
21- return {
22- self : id ,
23- parent : null ,
24- firstChild : null ,
25- previousSibling : null ,
26- nextSibling : null ,
27- level : 1 ,
28- } ;
29- }
30-
31- const roots : ResolverEvent [ ] = [ ] ;
3222
3323 for ( const process of processes ) {
3424 const uniqueProcessPid = uniquePidForProcess ( process ) ;
3525 idToValue . set ( uniqueProcessPid , process ) ;
3626
37- const currentProcessAdjacencyMap : AdjacentProcessMap =
38- idToAdjacent . get ( uniqueProcessPid ) || emptyAdjacencyMap ( uniqueProcessPid ) ;
39- idToAdjacent . set ( uniqueProcessPid , currentProcessAdjacencyMap ) ;
40-
4127 const uniqueParentPid = uniqueParentPidForProcess ( process ) ;
42- const currentProcessSiblings = idToChildren . get ( uniqueParentPid ) ;
43-
44- if ( currentProcessSiblings ) {
45- const previousProcessId = uniquePidForProcess (
46- currentProcessSiblings [ currentProcessSiblings . length - 1 ]
47- ) ;
48- currentProcessSiblings . push ( process ) ;
49- /**
50- * Update adjacency maps for current and previous entries
51- */
52- idToAdjacent . get ( previousProcessId ) ! . nextSibling = uniqueProcessPid ;
53- currentProcessAdjacencyMap . previousSibling = previousProcessId ;
54- if ( uniqueParentPid ) {
55- currentProcessAdjacencyMap . parent = uniqueParentPid ;
28+ // if its defined and not ''
29+ if ( uniqueParentPid ) {
30+ let siblings = idToChildren . get ( uniqueParentPid ) ;
31+ if ( ! siblings ) {
32+ siblings = [ ] ;
33+ idToChildren . set ( uniqueParentPid , siblings ) ;
5634 }
57- } else {
58- if ( uniqueParentPid ) {
59- idToChildren . set ( uniqueParentPid , [ process ] ) ;
60- /**
61- * Get the parent's map, otherwise set an empty one
62- */
63- const parentAdjacencyMap =
64- idToAdjacent . get ( uniqueParentPid ) ||
65- ( idToAdjacent . set ( uniqueParentPid , emptyAdjacencyMap ( uniqueParentPid ) ) ,
66- idToAdjacent . get ( uniqueParentPid ) ) ! ;
67- // set firstChild for parent
68- parentAdjacencyMap . firstChild = uniqueProcessPid ;
69- // set parent for current
70- currentProcessAdjacencyMap . parent = uniqueParentPid || null ;
71- } else {
72- // In this case (no unique parent id), it must be a root
73- roots . push ( process ) ;
74- }
75- }
76- }
77-
78- /**
79- * Scan adjacency maps from the top down and assign levels
80- */
81- function traverseLevels ( currentProcessMap : AdjacentProcessMap , level : number = 1 ) : void {
82- const nextLevel = level + 1 ;
83- if ( currentProcessMap . nextSibling ) {
84- traverseLevels ( idToAdjacent . get ( currentProcessMap . nextSibling ) ! , level ) ;
85- }
86- if ( currentProcessMap . firstChild ) {
87- traverseLevels ( idToAdjacent . get ( currentProcessMap . firstChild ) ! , nextLevel ) ;
35+ siblings . push ( process ) ;
8836 }
89- currentProcessMap . level = level ;
9037 }
9138
92- for ( const treeRoot of roots ) {
93- traverseLevels ( idToAdjacent . get ( uniquePidForProcess ( treeRoot ) ) ! ) ;
39+ // sort the children of each node
40+ for ( const siblings of idToChildren . values ( ) ) {
41+ siblings . sort ( orderByTime ) ;
9442 }
9543
9644 return {
9745 idToChildren,
9846 idToProcess : idToValue ,
99- idToAdjacent,
10047 } ;
10148}
10249
@@ -109,6 +56,13 @@ export function children(tree: IndexedProcessTree, process: ResolverEvent): Reso
10956 return currentProcessSiblings === undefined ? [ ] : currentProcessSiblings ;
11057}
11158
59+ /**
60+ * Get the indexed process event for the ID
61+ */
62+ export function processEvent ( tree : IndexedProcessTree , entityID : string ) : ResolverEvent | null {
63+ return tree . idToProcess . get ( entityID ) ?? null ;
64+ }
65+
11266/**
11367 * Returns the parent ProcessEvent, if any, for the passed in `childProcess`
11468 */
@@ -124,6 +78,31 @@ export function parent(
12478 }
12579}
12680
81+ /**
82+ * Returns the following sibling
83+ */
84+ export function nextSibling (
85+ tree : IndexedProcessTree ,
86+ sibling : ResolverEvent
87+ ) : ResolverEvent | undefined {
88+ const parentNode = parent ( tree , sibling ) ;
89+ if ( parentNode ) {
90+ // The siblings of `sibling` are the children of its parent.
91+ const siblings = children ( tree , parentNode ) ;
92+
93+ // Find the sibling
94+ const index = siblings . indexOf ( sibling ) ;
95+
96+ // if the sibling wasn't found, or if it was the last element in the array, return undefined
97+ if ( index === - 1 || index === siblings . length - 1 ) {
98+ return undefined ;
99+ }
100+
101+ // return the next sibling
102+ return siblings [ index + 1 ] ;
103+ }
104+ }
105+
127106/**
128107 * Number of processes in the tree
129108 */
@@ -138,7 +117,10 @@ export function root(tree: IndexedProcessTree) {
138117 if ( size ( tree ) === 0 ) {
139118 return null ;
140119 }
120+ // any node will do
141121 let current : ResolverEvent = tree . idToProcess . values ( ) . next ( ) . value ;
122+
123+ // iteratively swap current w/ its parent
142124 while ( parent ( tree , current ) !== undefined ) {
143125 current = parent ( tree , current ) ! ;
144126 }
0 commit comments