46 /** |
46 /** |
47 * Parses a chunk. |
47 * Parses a chunk. |
48 * |
48 * |
49 */ |
49 */ |
50 final class ChunkParser { |
50 final class ChunkParser { |
|
51 |
|
52 static final class ParserConfiguration { |
|
53 final boolean reuse; |
|
54 final boolean ordered; |
|
55 final InternalEventFilter eventFilter; |
|
56 |
|
57 long filterStart; |
|
58 long filterEnd; |
|
59 |
|
60 public ParserConfiguration(long filterStart, long filterEnd, boolean reuse, boolean ordered, InternalEventFilter filter) { |
|
61 this.filterStart = filterStart; |
|
62 this.filterEnd = filterEnd; |
|
63 this.reuse = reuse; |
|
64 this.ordered = ordered; |
|
65 this.eventFilter = filter; |
|
66 } |
|
67 |
|
68 public ParserConfiguration() { |
|
69 this(0, Long.MAX_VALUE, false, false, InternalEventFilter.ACCEPT_ALL); |
|
70 } |
|
71 } |
|
72 |
51 // Checkpoint that finishes a flush segment |
73 // Checkpoint that finishes a flush segment |
52 static final byte CHECKPOINT_FLUSH_MASK = 1; |
74 static final byte CHECKPOINT_FLUSH_MASK = 1; |
53 // Checkpoint contains chunk header information in the first pool |
75 // Checkpoint contains chunk header information in the first pool |
54 static final byte CHECKPOINT_CHUNK_HEADER_MASK = 2; |
76 static final byte CHECKPOINT_CHUNK_HEADER_MASK = 2; |
55 // Checkpoint contains only statics that will not change from chunk to chunk |
77 // Checkpoint contains only statics that will not change from chunk to chunk |
68 private final LongMap<ConstantLookup> constantLookups; |
90 private final LongMap<ConstantLookup> constantLookups; |
69 |
91 |
70 private LongMap<Type> typeMap; |
92 private LongMap<Type> typeMap; |
71 private LongMap<Parser> parsers; |
93 private LongMap<Parser> parsers; |
72 private boolean chunkFinished; |
94 private boolean chunkFinished; |
73 private InternalEventFilter eventFilter = InternalEventFilter.ACCEPT_ALL; |
95 |
74 private boolean reuse; |
|
75 private boolean ordered; |
|
76 private boolean resetEventCache; |
|
77 private long filterStart = 0; |
|
78 private long filterEnd = Long.MAX_VALUE; |
|
79 private Runnable flushOperation; |
96 private Runnable flushOperation; |
80 |
97 private ParserConfiguration configuration; |
81 public ChunkParser(RecordingInput input, boolean reuse) throws IOException { |
98 |
82 this(new ChunkHeader(input), null, 1000); |
99 public ChunkParser(RecordingInput input) throws IOException { |
83 this.reuse = reuse; |
100 this(input, new ParserConfiguration()); |
|
101 } |
|
102 |
|
103 public ChunkParser(RecordingInput input, ParserConfiguration pc) throws IOException { |
|
104 this(new ChunkHeader(input), null, pc); |
84 } |
105 } |
85 |
106 |
86 public ChunkParser(ChunkParser previous) throws IOException { |
107 public ChunkParser(ChunkParser previous) throws IOException { |
87 this(new ChunkHeader(previous.input), previous, 1000); |
108 this(new ChunkHeader(previous.input), previous, new ParserConfiguration()); |
88 } |
109 } |
89 |
110 |
90 private ChunkParser(ChunkHeader header, ChunkParser previous, long pollInterval) throws IOException { |
111 private ChunkParser(ChunkHeader header, ChunkParser previous, ParserConfiguration pc) throws IOException { |
|
112 this.configuration = pc; |
91 this.input = header.getInput(); |
113 this.input = header.getInput(); |
92 this.chunkHeader = header; |
114 this.chunkHeader = header; |
93 if (previous == null) { |
115 if (previous == null) { |
94 this.pollInterval = 1000; |
116 this.pollInterval = 1000; |
95 this.constantLookups = new LongMap<>(); |
117 this.constantLookups = new LongMap<>(); |
96 this.previousMetadata = null; |
118 this.previousMetadata = null; |
97 } else { |
119 } else { |
98 this.constantLookups = previous.constantLookups; |
120 this.constantLookups = previous.constantLookups; |
99 this.previousMetadata = previous.metadata; |
121 this.previousMetadata = previous.metadata; |
100 this.pollInterval = previous.pollInterval; |
122 this.pollInterval = previous.pollInterval; |
101 this.ordered = previous.ordered; |
123 this.configuration = previous.configuration; |
102 this.reuse = previous.reuse; |
|
103 this.eventFilter = previous.eventFilter; |
|
104 } |
124 } |
105 this.metadata = header.readMetadata(previousMetadata); |
125 this.metadata = header.readMetadata(previousMetadata); |
106 this.timeConverter = new TimeConverter(chunkHeader, metadata.getGMTOffset()); |
126 this.timeConverter = new TimeConverter(chunkHeader, metadata.getGMTOffset()); |
107 if (metadata != previousMetadata) { |
127 if (metadata != previousMetadata) { |
108 ParserFactory factory = new ParserFactory(metadata, constantLookups, timeConverter); |
128 ParserFactory factory = new ParserFactory(metadata, constantLookups, timeConverter); |
109 parsers = factory.getParsers(); |
129 parsers = factory.getParsers(); |
110 typeMap = factory.getTypeMap(); |
130 typeMap = factory.getTypeMap(); |
111 updateEventParsers(); |
131 updateConfiguration(); |
112 } else { |
132 } else { |
113 parsers = previous.parsers; |
133 parsers = previous.parsers; |
114 typeMap = previous.typeMap; |
134 typeMap = previous.typeMap; |
115 } |
135 } |
116 constantLookups.forEach(c -> c.newPool()); |
136 constantLookups.forEach(c -> c.newPool()); |
120 constantLookups.forEach(c -> c.getLatestPool().setResolved()); |
140 constantLookups.forEach(c -> c.getLatestPool().setResolved()); |
121 |
141 |
122 input.position(chunkHeader.getEventStart()); |
142 input.position(chunkHeader.getEventStart()); |
123 } |
143 } |
124 |
144 |
125 public void setParserFilter(InternalEventFilter filter) { |
145 public ChunkParser nextChunkParser() throws IOException { |
126 this.eventFilter = filter; |
146 return new ChunkParser(chunkHeader.nextHeader(), this, configuration); |
127 } |
147 } |
128 |
148 |
129 public InternalEventFilter getEventFilter() { |
149 private void updateConfiguration() { |
130 return this.eventFilter; |
150 updateConfiguration(configuration, false); |
|
151 } |
|
152 |
|
153 public void updateConfiguration(ParserConfiguration configuration, boolean resetEventCache) { |
|
154 this.configuration = configuration; |
|
155 parsers.forEach(p -> { |
|
156 if (p instanceof EventParser) { |
|
157 EventParser ep = (EventParser) p; |
|
158 if (resetEventCache) { |
|
159 ep.resetCache(); |
|
160 } |
|
161 String name = ep.getEventType().getName(); |
|
162 ep.setOrdered(configuration.ordered); |
|
163 ep.setReuse(configuration.reuse); |
|
164 ep.setFilterStart(configuration.filterStart); |
|
165 ep.setFilterEnd(configuration.filterEnd); |
|
166 long threshold = configuration.eventFilter.getThreshold(name); |
|
167 if (threshold >= 0) { |
|
168 ep.setEnabled(true); |
|
169 ep.setThresholdNanos(threshold); |
|
170 } else { |
|
171 ep.setEnabled(false); |
|
172 ep.setThresholdNanos(Long.MAX_VALUE); |
|
173 } |
|
174 } |
|
175 }); |
131 } |
176 } |
132 |
177 |
133 /** |
178 /** |
134 * Reads an event and returns null when segment or chunk ends. |
179 * Reads an event and returns null when segment or chunk ends. |
135 * |
180 * |
159 Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Found new metadata in chunk. Rebuilding types and parsers"); |
204 Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Found new metadata in chunk. Rebuilding types and parsers"); |
160 MetadataDescriptor metadata = chunkHeader.readMetadata(previousMetadata); |
205 MetadataDescriptor metadata = chunkHeader.readMetadata(previousMetadata); |
161 ParserFactory factory = new ParserFactory(metadata, constantLookups, timeConverter); |
206 ParserFactory factory = new ParserFactory(metadata, constantLookups, timeConverter); |
162 parsers = factory.getParsers(); |
207 parsers = factory.getParsers(); |
163 typeMap = factory.getTypeMap(); |
208 typeMap = factory.getTypeMap(); |
164 updateEventParsers(); |
209 updateConfiguration();; |
165 } |
210 } |
166 if (contantPosition != chunkHeader.getConstantPoolPosition()) { |
211 if (contantPosition != chunkHeader.getConstantPoolPosition()) { |
167 Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Found new constant pool data. Filling up pools with new values"); |
212 Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Found new constant pool data. Filling up pools with new values"); |
168 constantLookups.forEach(c -> c.getLatestPool().setAllResolved(false)); |
213 constantLookups.forEach(c -> c.getLatestPool().setAllResolved(false)); |
169 fillConstantPools(contantPosition + chunkHeader.getAbsoluteChunkStart()); |
214 fillConstantPools(contantPosition + chunkHeader.getAbsoluteChunkStart()); |
370 |
415 |
371 public ChunkParser newChunkParser() throws IOException { |
416 public ChunkParser newChunkParser() throws IOException { |
372 return new ChunkParser(this); |
417 return new ChunkParser(this); |
373 } |
418 } |
374 |
419 |
375 public ChunkParser nextChunkParser() throws IOException { |
|
376 return new ChunkParser(chunkHeader.nextHeader(), this, pollInterval); |
|
377 } |
|
378 |
|
379 public boolean isChunkFinished() { |
420 public boolean isChunkFinished() { |
380 return chunkFinished; |
421 return chunkFinished; |
381 } |
422 } |
382 |
423 |
383 // Need to call updateEventParsers() for |
|
384 // change to take effect |
|
385 public void setReuse(boolean resue) { |
|
386 this.reuse = resue; |
|
387 } |
|
388 |
|
389 public void setFlushOperation(Runnable flushOperation) { |
424 public void setFlushOperation(Runnable flushOperation) { |
390 this.flushOperation = flushOperation; |
425 this.flushOperation = flushOperation; |
391 } |
426 } |
392 |
427 |
393 // Need to call updateEventParsers() for |
|
394 // change to take effect |
|
395 public void setOrdered(boolean ordered) { |
|
396 this.ordered = ordered; |
|
397 } |
|
398 |
|
399 // Need to call updateEventParsers() for |
|
400 // change to take effect |
|
401 public void setFilterStart(long filterStart) { |
|
402 long chunkStart = chunkHeader.getStartNanos(); |
|
403 // Optimization. |
|
404 if (filterStart < chunkStart - 1_000_000_000L) { |
|
405 filterStart = 0; |
|
406 } |
|
407 this.filterStart = filterStart; |
|
408 } |
|
409 |
|
410 public void setFilterEnd(long filterEnd) { |
|
411 this.filterEnd = filterEnd; |
|
412 } |
|
413 |
|
414 // Need to call updateEventParsers() for |
|
415 // change to take effect |
|
416 public void resetEventCache() { |
|
417 this.resetEventCache = true; |
|
418 } |
|
419 |
|
420 public void updateEventParsers() { |
|
421 parsers.forEach(p -> { |
|
422 if (p instanceof EventParser) { |
|
423 EventParser ep = (EventParser) p; |
|
424 String name = ep.getEventType().getName(); |
|
425 ep.setOrdered(ordered); |
|
426 ep.setReuse(reuse); |
|
427 ep.setFilterStart(filterStart); |
|
428 ep.setFilterEnd(filterEnd); |
|
429 if (resetEventCache) { |
|
430 ep.resetCache(); |
|
431 } |
|
432 long threshold = eventFilter.getThreshold(name); |
|
433 if (threshold >= 0) { |
|
434 ep.setEnabled(true); |
|
435 ep.setThresholdNanos(threshold); |
|
436 } else { |
|
437 ep.setEnabled(false); |
|
438 ep.setThresholdNanos(Long.MAX_VALUE); |
|
439 } |
|
440 } |
|
441 }); |
|
442 resetEventCache = false; |
|
443 } |
|
444 |
|
445 public long getChunkDuration() { |
428 public long getChunkDuration() { |
446 return chunkHeader.getDurationNanos(); |
429 return chunkHeader.getDurationNanos(); |
447 } |
430 } |
448 |
431 |
449 public long getStartNanos() { |
432 public long getStartNanos() { |
450 return chunkHeader.getStartNanos(); |
433 return chunkHeader.getStartNanos(); |
451 } |
434 } |
|
435 |
452 } |
436 } |