src/jdk.jfr/share/classes/jdk/jfr/consumer/ConstantMap.java
branchJEP-349-branch
changeset 57360 5d043a159d5c
parent 50113 caf115bb98ad
child 57373 400db63e4937
equal deleted inserted replaced
57359:4cab5edc2950 57360:5d043a159d5c
     1 /*
     1 /*
     2  * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    23  * questions.
    23  * questions.
    24  */
    24  */
    25 
    25 
    26 package jdk.jfr.consumer;
    26 package jdk.jfr.consumer;
    27 
    27 
    28 import java.util.ArrayList;
       
    29 import java.util.List;
       
    30 
       
    31 /**
    28 /**
    32  * Holds mapping between a set of keys and their corresponding object.
    29  * Holds mapping between a set of keys and their corresponding object.
    33  *
    30  *
    34  * If the type is a known type, i.e. {@link RecordedThread}, an
    31  * If the type is a known type, i.e. {@link RecordedThread}, an
    35  * {@link ObjectFactory} can be supplied which will instantiate a typed object.
    32  * {@link ObjectFactory} can be supplied which will instantiate a typed object.
    36  */
    33  */
    37 final class ConstantMap {
    34 final class ConstantMap {
       
    35 
       
    36     private static final int RESOLUTION_FINISHED = 0;
       
    37     private static final int RESOLUTION_STARTED = 1;
       
    38     public static final ConstantMap EMPTY = new ConstantMap();
       
    39 
       
    40     // A temporary placeholder, so objects can
       
    41     // reference themselves (directly, or indirectly),
       
    42     // when making a transition from numeric id references
       
    43     // to normal Java references.
    38     private final static class Reference {
    44     private final static class Reference {
    39         private final long key;
    45         private final long key;
    40         private final ConstantMap pool;
    46         private final ConstantMap pool;
    41 
    47 
    42         Reference(ConstantMap pool, long key) {
    48         Reference(ConstantMap pool, long key) {
    45         }
    51         }
    46 
    52 
    47         Object resolve() {
    53         Object resolve() {
    48             return pool.get(key);
    54             return pool.get(key);
    49         }
    55         }
       
    56 
       
    57         public String toString() {
       
    58             return "ref: " + pool.name + "[" + key + "]";
       
    59         }
    50     }
    60     }
    51 
    61 
    52     private final ObjectFactory<?> factory;
    62     final ObjectFactory<?> factory;
       
    63     final String name;
       
    64 
    53     private final LongMap<Object> objects;
    65     private final LongMap<Object> objects;
    54 
    66 
    55     private LongMap<Boolean> isResolving;
    67     private boolean resolving;
    56     private boolean allResolved;
    68     private boolean allResolved;
    57     private String name;
    69 
       
    70     private ConstantMap() {
       
    71         this(null, "<empty>");
       
    72         allResolved = true;
       
    73     }
    58 
    74 
    59     ConstantMap(ObjectFactory<?> factory, String name) {
    75     ConstantMap(ObjectFactory<?> factory, String name) {
    60         this.name = name;
    76         this.name = name;
    61         this.objects = new LongMap<>();
    77         this.objects = new LongMap<>(2);
    62         this.factory = factory;
    78         this.factory = factory;
    63     }
    79     }
    64 
    80 
    65     Object get(long id) {
    81     Object get(long id) {
    66         // fast path, all objects in pool resolved
    82         // fast path, all objects in pool resolved
    67         if (allResolved) {
    83         if (allResolved) {
    68             return objects.get(id);
    84             return objects.get(id);
    69         }
    85         }
    70         // referenced from a pool, deal with this later
    86         // referenced from a pool, deal with this later
    71         if (isResolving == null) {
    87         if (!resolving) {
    72             return new Reference(this, id);
    88             return new Reference(this, id);
    73         }
    89         }
    74 
    90 
    75         Boolean beingResolved = isResolving.get(id);
    91         // should always have a value
       
    92         Object value = objects.get(id);
       
    93         if (value == null) {
       
    94             // unless is 0 which is used to represent null
       
    95             if (id == 0) {
       
    96                 return null;
       
    97             }
       
    98             throw new InternalError("Missing object id=" + id + " in pool " + name + ". All ids should reference object");
       
    99         }
    76 
   100 
    77         // we are resolved (but not the whole pool)
   101         // id is resolved (but not the whole pool)
    78         if (Boolean.FALSE.equals(beingResolved)) {
   102         if (objects.isSetId(id, RESOLUTION_FINISHED)) {
    79             return objects.get(id);
   103             return value;
    80         }
   104         }
    81 
   105 
    82         // resolving ourself, abort to avoid infinite recursion
   106         // resolving ourself, abort to avoid infinite recursion
    83         if (Boolean.TRUE.equals(beingResolved)) {
   107         if (objects.isSetId(id, RESOLUTION_STARTED)) {
    84             return null;
   108             return null;
    85         }
   109         }
    86 
   110 
    87         // resolve me!
   111         // mark id as STARTED if we should
    88         isResolving.put(id, Boolean.TRUE);
   112         // come back during object resolution
    89         Object resolved = resolve(objects.get(id));
   113         objects.setId(id, RESOLUTION_STARTED);
    90         isResolving.put(id, Boolean.FALSE);
   114 
       
   115         // resolve object!
       
   116         Object resolved = resolve(value);
       
   117 
       
   118         // mark id as FINISHED
       
   119         objects.setId(id, RESOLUTION_FINISHED);
       
   120 
       
   121         // if a factory exists, convert to RecordedThread.
       
   122         // RecordedClass etc. and store back results
    91         if (factory != null) {
   123         if (factory != null) {
    92             Object factorized = factory.createObject(id, resolved);
   124             Object factorized = factory.createObject(id, resolved);
    93             objects.put(id, factorized);
   125             objects.put(id, factorized);
    94             return factorized;
   126             return factorized;
    95         } else {
   127         } else {
   103             return resolve(((Reference) o).resolve());
   135             return resolve(((Reference) o).resolve());
   104         }
   136         }
   105         if (o != null && o.getClass().isArray()) {
   137         if (o != null && o.getClass().isArray()) {
   106             final Object[] array = (Object[]) o;
   138             final Object[] array = (Object[]) o;
   107             for (int i = 0; i < array.length; i++) {
   139             for (int i = 0; i < array.length; i++) {
   108                 array[i] = resolve(array[i]);
   140                 Object element = array[i];
       
   141                 array[i] = resolve(element);
   109             }
   142             }
   110             return array;
   143             return array;
   111         }
   144         }
   112         return o;
   145         return o;
   113     }
   146     }
   114 
   147 
   115     public void resolve() {
   148     public void resolve() {
   116         List<Long> keyList = new ArrayList<>();
   149         objects.forEachKey(k -> get(k));
   117         objects.keys().forEachRemaining(keyList::add);
       
   118         for (Long l : keyList) {
       
   119             get(l);
       
   120         }
       
   121     }
   150     }
   122 
   151 
   123     public void put(long key, Object value) {
   152     public void put(long key, Object value) {
   124         objects.put(key, value);
   153         objects.put(key, value);
   125     }
   154     }
   126 
   155 
   127     public void setIsResolving() {
   156     public void setResolving() {
   128         isResolving = new LongMap<>();
   157         resolving = true;
       
   158         allResolved = false;
   129     }
   159     }
   130 
   160 
   131     public void setResolved() {
   161     public void setResolved() {
   132         allResolved = true;
   162         allResolved = true;
   133         isResolving = null; // pool finished, release memory
   163         resolving = false;
   134     }
   164     }
   135 
   165 
   136     public String getName() {
   166     public String getName() {
   137         return name;
   167         return name;
   138     }
   168     }
       
   169 
       
   170     public Object getResolved(long id) {
       
   171         return objects.get(id);
       
   172     }
       
   173 
       
   174     public void putResolved(long id, Object object) {
       
   175         objects.setId(id, RESOLUTION_FINISHED);
       
   176         objects.put(id, object);
       
   177     }
       
   178 
       
   179     public void setAllResolved(boolean allResolved) {
       
   180         this.allResolved = allResolved;
       
   181     }
       
   182 
       
   183     public boolean isResolved(long id) {
       
   184         if (objects.hasKey(id)) {
       
   185             return objects.isSetId(id, RESOLUTION_FINISHED);
       
   186         }
       
   187         return false;
       
   188     }
   139 }
   189 }