37
37
import java .util .Map ;
38
38
import java .util .Objects ;
39
39
import java .util .Set ;
40
- import java .util .WeakHashMap ;
41
40
import java .util .concurrent .atomic .AtomicBoolean ;
42
41
import java .util .function .Supplier ;
43
42
import java .util .logging .Handler ;
@@ -926,62 +925,57 @@ public void close() {
926
925
}
927
926
928
927
static final class LoggerCache {
928
+ private static final ReferenceQueue <Object > contextsRefQueue = new ReferenceQueue <>();
929
929
private static final LoggerCache INSTANCE = new LoggerCache ();
930
930
private final TruffleLogger polyglotRootLogger ;
931
931
private final Map <String , NamedLoggerRef > loggers ;
932
932
private final LoggerNode root ;
933
- private final Map < Object , Map < String , Level >> levelsByContext ;
933
+ private final Set < ContextWeakReference > activeContexts ;
934
934
private Map <String , Level > effectiveLevels ;
935
935
936
936
private LoggerCache () {
937
937
this .polyglotRootLogger = new TruffleLogger ();
938
938
this .loggers = new HashMap <>();
939
939
this .loggers .put (ROOT_NAME , new NamedLoggerRef (this .polyglotRootLogger , ROOT_NAME ));
940
940
this .root = new LoggerNode (null , new NamedLoggerRef (this .polyglotRootLogger , ROOT_NAME ));
941
- this .levelsByContext = new WeakHashMap <>();
941
+ this .activeContexts = new HashSet <>();
942
942
this .effectiveLevels = Collections .emptyMap ();
943
943
}
944
944
945
- void addLogLevelsForContext (final Object context , final Map <String , Level > addedLevels ) {
946
- synchronized (this ) {
947
- levelsByContext .put (context , addedLevels );
948
- final Collection <String > removedLevels = new HashSet <>();
949
- final Collection <String > changedLevels = new HashSet <>();
950
- effectiveLevels = computeEffectiveLevels (
951
- effectiveLevels ,
952
- Collections .emptySet (),
953
- addedLevels ,
954
- levelsByContext ,
955
- removedLevels ,
956
- changedLevels );
957
- reconfigure (removedLevels , changedLevels );
958
- }
945
+ synchronized void addLogLevelsForContext (final Object context , final Map <String , Level > addedLevels ) {
946
+ activeContexts .add (new ContextWeakReference (context , contextsRefQueue , addedLevels ));
947
+ final Set <String > toRemove = collectRemovedLevels ();
948
+ reconfigure (addedLevels , toRemove );
959
949
}
960
950
961
951
synchronized void removeLogLevelsForContext (final Object context ) {
962
- final Map <String , Level > levels = levelsByContext .remove (context );
963
- final Collection <String > removedLevels = new HashSet <>();
964
- final Collection <String > changedLevels = new HashSet <>();
965
- effectiveLevels = computeEffectiveLevels (
966
- effectiveLevels ,
967
- levels .keySet (),
968
- Collections .emptyMap (),
969
- levelsByContext ,
970
- removedLevels ,
971
- changedLevels );
972
- reconfigure (removedLevels , changedLevels );
952
+ final Set <String > toRemove = collectRemovedLevels ();
953
+ for (Iterator <ContextWeakReference > it = activeContexts .iterator (); it .hasNext ();) {
954
+ final Object activeContext = it .next ().get ();
955
+ if (context .equals (activeContext )) {
956
+ toRemove .addAll (TruffleLanguage .AccessAPI .engineAccess ().getLogLevels (context ).keySet ());
957
+ it .remove ();
958
+ break ;
959
+ }
960
+ }
961
+ reconfigure (Collections .emptyMap (), toRemove );
973
962
}
974
963
975
964
synchronized boolean isLoggable (final String loggerName , final Object currentContext , final Level level ) {
976
- final Map <String , Level > current = levelsByContext .get (currentContext );
977
- if (current == null ) {
965
+ final Set <String > toRemove = collectRemovedLevels ();
966
+ if (!toRemove .isEmpty ()) {
967
+ reconfigure (Collections .emptyMap (), toRemove );
968
+ // Logger's effective level may changed
969
+ return getLogger (loggerName ).isLoggable (level );
970
+ }
971
+ final Map <String , Level > current = TruffleLanguage .AccessAPI .engineAccess ().getLogLevels (currentContext );
972
+ if (current .isEmpty ()) {
978
973
final int currentLevel = DEFAULT_VALUE ;
979
974
return level .intValue () >= currentLevel && currentLevel != OFF_VALUE ;
980
975
}
981
- // GR-10762 does not work if contexts are GCed
982
- // if (levelsByContext.size() == 1) {
983
- // return true;
984
- // }
976
+ if (activeContexts .size () == 1 ) {
977
+ return true ;
978
+ }
985
979
final int currentLevel = Math .min (computeLevel (loggerName , current ), DEFAULT_VALUE );
986
980
return level .intValue () >= currentLevel && currentLevel != OFF_VALUE ;
987
981
}
@@ -1064,14 +1058,36 @@ private Level getEffectiveLevel(final String loggerName) {
1064
1058
return effectiveLevels .get (loggerName );
1065
1059
}
1066
1060
1067
- private void reconfigure (final Collection <? extends String > removedLoggers , final Collection <? extends String > changedLoogers ) {
1068
- for (String loggerName : removedLoggers ) {
1061
+ private Set <String > collectRemovedLevels () {
1062
+ assert Thread .holdsLock (this );
1063
+ final Set <String > toRemove = new HashSet <>();
1064
+ ContextWeakReference ref ;
1065
+ while ((ref = (ContextWeakReference ) contextsRefQueue .poll ()) != null ) {
1066
+ activeContexts .remove (ref );
1067
+ toRemove .addAll (ref .configuredLoggerNames );
1068
+ }
1069
+ return toRemove ;
1070
+ }
1071
+
1072
+ private void reconfigure (final Map <String , Level > addedLevels , final Set <String > toRemove ) {
1073
+ assert Thread .holdsLock (this );
1074
+ assert !addedLevels .isEmpty () || !toRemove .isEmpty ();
1075
+ final Collection <String > loggersWithRemovedLevels = new HashSet <>();
1076
+ final Collection <String > loggersWithChangedLevels = new HashSet <>();
1077
+ effectiveLevels = computeEffectiveLevels (
1078
+ effectiveLevels ,
1079
+ toRemove ,
1080
+ addedLevels ,
1081
+ activeContexts ,
1082
+ loggersWithRemovedLevels ,
1083
+ loggersWithChangedLevels );
1084
+ for (String loggerName : loggersWithRemovedLevels ) {
1069
1085
final TruffleLogger logger = getLogger (loggerName );
1070
1086
if (logger != null ) {
1071
1087
logger .setLevel (null );
1072
1088
}
1073
1089
}
1074
- for (String loggerName : changedLoogers ) {
1090
+ for (String loggerName : loggersWithChangedLevels ) {
1075
1091
final TruffleLogger logger = getLogger (loggerName );
1076
1092
if (logger != null ) {
1077
1093
setLoggerLevel (logger , loggerName );
@@ -1137,18 +1153,18 @@ private static Map<String, Level> computeEffectiveLevels(
1137
1153
final Map <String , Level > currentEffectiveLevels ,
1138
1154
final Set <String > removed ,
1139
1155
final Map <String , Level > added ,
1140
- final Map < Object , Map < String , Level >> levelsByContext ,
1156
+ final Collection <? extends Reference < Object >> contexts ,
1141
1157
final Collection <? super String > removedLevels ,
1142
1158
final Collection <? super String > changedLevels ) {
1143
1159
final Map <String , Level > newEffectiveLevels = new HashMap <>(currentEffectiveLevels );
1144
1160
for (String loggerName : removed ) {
1145
- final Level level = findMinLevel (loggerName , levelsByContext );
1161
+ final Level level = findMinLevel (loggerName , contexts );
1146
1162
if (level == null ) {
1147
1163
newEffectiveLevels .remove (loggerName );
1148
1164
removedLevels .add (loggerName );
1149
1165
} else {
1150
1166
final Level currentLevel = newEffectiveLevels .get (loggerName );
1151
- if (min ( level , currentLevel ) != currentLevel ) {
1167
+ if (currentLevel != level ) {
1152
1168
newEffectiveLevels .put (loggerName , level );
1153
1169
changedLevels .add (loggerName );
1154
1170
}
@@ -1166,10 +1182,11 @@ private static Map<String, Level> computeEffectiveLevels(
1166
1182
return newEffectiveLevels ;
1167
1183
}
1168
1184
1169
- private static Level findMinLevel (final String loggerName , final Map < Object , Map < String , Level >> levelsByContext ) {
1185
+ private static Level findMinLevel (final String loggerName , final Collection <? extends Reference < Object >> contexts ) {
1170
1186
Level min = null ;
1171
- for (Map <String , Level > levels : levelsByContext .values ()) {
1172
- Level level = levels .get (loggerName );
1187
+ for (Reference <Object > contextRef : contexts ) {
1188
+ final Object context = contextRef .get ();
1189
+ final Level level = context == null ? null : TruffleLanguage .AccessAPI .engineAccess ().getLogLevels (context ).get (loggerName );
1173
1190
if (level == null ) {
1174
1191
continue ;
1175
1192
}
@@ -1259,6 +1276,15 @@ private void updateChildParentsImpl(final TruffleLogger parentLogger) {
1259
1276
}
1260
1277
}
1261
1278
}
1279
+
1280
+ private static final class ContextWeakReference extends WeakReference <Object > {
1281
+ private final Set <String > configuredLoggerNames ;
1282
+
1283
+ ContextWeakReference (final Object context , final ReferenceQueue <Object > referenceQueue , final Map <String , Level > logLevels ) {
1284
+ super (context , referenceQueue );
1285
+ configuredLoggerNames = logLevels .keySet ();
1286
+ }
1287
+ }
1262
1288
}
1263
1289
1264
1290
private static final class PolyglotLogHandlerProvider implements Supplier <Handler > {
0 commit comments