Skip to content

Commit

Permalink
Order keys by mru parse rule (#295)
Browse files Browse the repository at this point in the history
  • Loading branch information
dsgrieve committed Jun 13, 2023
1 parent f49a8f9 commit 07194a2
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import java.util.AbstractMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Optional;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
Expand Down Expand Up @@ -174,18 +173,24 @@ protected void process(String line) {
}

private void parse(String line) {
Optional<AbstractMap.SimpleEntry<GCParseRule, GCLogTrace>> ruleToApply = parseRules.keys().stream()
parseRules.stream()
.map(Map.Entry::getKey)
.map(rule -> new AbstractMap.SimpleEntry<>(rule, rule.parse(line)))
.filter(tuple -> tuple.getValue() != null)
.findFirst();
if (!ruleToApply.isPresent()) {
log(line);
return;
}
.findAny()
.ifPresentOrElse(
tuple -> {
applyRule(tuple.getKey(), tuple.getValue(), line);
},
() -> log(line)
);
}


private void applyRule(GCParseRule ruleToApply, GCLogTrace trace, String line) {
try {
setForwardReference(line);
parseRules.get(ruleToApply.get().getKey()).accept(ruleToApply.get().getValue(), line);
parseRules.select(ruleToApply).accept(trace, line);
} catch (Throwable t) {
LOGGER.throwing(this.getName(), "process", t);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.logging.Level;
Expand Down Expand Up @@ -127,15 +126,23 @@ protected void process(String line) {

if (ignoreFrequentlySeenButUnwantedLines(line)) return;

Optional<AbstractMap.SimpleEntry<GCParseRule, GCLogTrace>> ruleToApply = parseRules.keys().stream()
parseRules.stream()
.map(Map.Entry::getKey)
.map(rule -> new AbstractMap.SimpleEntry<>(rule, rule.parse(line)))
.filter(tuple -> tuple.getValue() != null)
.findFirst();
.findAny()
.ifPresentOrElse(
tuple -> {
applyRule(tuple.getKey(), tuple.getValue(), line);
},
() -> LOGGER.log(Level.FINE, "Missed: {0}", line)
);
}


private void applyRule(GCParseRule ruleToApply, GCLogTrace trace, String line) {
try {
if (ruleToApply.isPresent())
parseRules.get(ruleToApply.get().getKey()).accept(ruleToApply.get().getValue(), line);
else
LOGGER.log(Level.FINE, "Missed: {0}", line);
parseRules.select(ruleToApply).accept(trace, line);
} catch (Throwable t) {
LOGGER.throwing(this.getName(), "process", t);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,10 @@ protected void process(String entry) {
} else if ((trace = AGE_TABLE_HEADER.parse(entry)) != null) {
//we've collected this data so.. eat it...
} else if ((trace = AGE_RECORD.parse(entry)) != null) {
forwardReference.add(trace.getIntegerGroup(1), trace.getLongGroup(2));
ageDataCollected = true;
if (forwardReference != null) {
forwardReference.add(trace.getIntegerGroup(1), trace.getLongGroup(2));
ageDataCollected = true;
}
} else if (entry.equals(END_OF_DATA_SENTINEL) || (JVM_EXIT.parse(entry) != null)) {
if (forwardReference != null)
publish(forwardReference);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,45 @@
// Licensed under the MIT License.
package com.microsoft.gctoolkit.parser.collection;

import java.util.AbstractMap;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Stream;

public class RuleSet<K, V> implements Map<K, V>, Iterable<K> {

private final HashMap<K, V> entries;
private final LinkedList<K> keys;
private static class Node<K, V> extends AbstractMap.SimpleImmutableEntry<K,V> {

private Node<K, V> next;
private Node<K, V> prev;

public Node(K key, V value) {
super(key, value);
}
}

// Instead of a java.util.LinkedList, we use a doubly-linked list of nodes.
// This allows us to move the most-recently selected node from to the head of
// the list in O(1) time, instead of O(n) time.
private Node<K,V> head;

private final HashMap<K, Node<K,V>> entries;

public RuleSet() {
entries = new HashMap<>();
keys = new LinkedList<>();
}

public V get(Object key) {
if (key != null) {
return entries.get(key);
Node<K,V> node = entries.get(key);
return node.getValue();
}
return null;
}
Expand All @@ -49,8 +67,15 @@ public boolean containsValue(Object value) {

@Override
public V put(K key, V value) {
entries.put(key, value);
keys.offer(key);
Node<K,V> node = new Node<>(key, value);
if (head == null) {
head = node;
} else {
node.next = head;
head.prev = node;
head = node;
}
entries.put(key, node);
return value;
}

Expand All @@ -76,20 +101,74 @@ public Set<K> keySet() {

@Override
public Collection<V> values() {
return entries.values();
Collection<V> values = new LinkedList<>();
for (Node<K,V> node = head; node != null; node = node.next) {
values.add(node.getValue());
}
return values;
}

@Override
public Set<Entry<K, V>> entrySet() {
return entries.entrySet();
Set<Entry<K,V>> entrySet = new HashSet<>();
for (Node<K,V> node = head; node != null; node = node.next) {
entrySet.add(node);
}
return entrySet;
}

public List<K> keys() {
return keys;
public Stream<Entry<K,V>> stream() {
return Stream.iterate(head, Objects::nonNull, node -> ((Node<K,V>)node).next);
}

private class KeyIterator implements Iterator<K> {
private Node<K, V> node;

public KeyIterator() {
node = head;
}

@Override
public boolean hasNext() {
return node != null;
}

@Override
public K next() {
if (node == null) {
// per the Iterator contract
throw new NoSuchElementException();
}
Node<K, V> current = node;
node = node.next;
return current.getKey();
}

}

@Override
public Iterator<K> iterator() {
return keys.iterator();
return new KeyIterator();
}

public V select(K key) {
// When a key is selected, move it to the head of the list.
// The list will be ordered from most-recently selected to least-recently selected.
// Side note: attempting to sort by most often selected resulted in worse performance.
final Node<K,V> selected = entries.get(key);
if (selected != head) {
if (selected.next != null) {
Node<K, V> next = selected.next;
next.prev = selected.prev;
}
if (selected.prev != null) {
Node<K, V> prev = selected.prev;
prev.next = selected.next;
}
head.prev = selected;
selected.next = head;
head = selected;
}
return selected.getValue();
}
}

0 comments on commit 07194a2

Please sign in to comment.