I split this one up by accident. There was a follow up commit that updated the places where they were updated in main. I don’t recall any particular issue being resolved, though I was comparing the 2.x and main branches to look for differences. Guess I did it in reverse here. — Matt Sicker
> On Nov 5, 2023, at 00:08, Ralph Goers <ralph.go...@dslextreme.com> wrote: > > Matt, > > I received 3 emails regarding this lazy stuff being back ported. Is there a > related issue for this? With the volume of emails I am getting I may have > missed it but I would like to understand, Furthermore, in none of these > commit emails did I see a changes file listed? How can I know why you did > this without that and user’s won’t either since it won’t appear in the > release notes. > > Note that while I would like to avoid back porting from 3.x if it is being > done to resolve a bug then I am fine with that. But if this is just a random > “improvement” please don’t. > > Ralph > >> On Nov 3, 2023, at 4:22 PM, mattsic...@apache.org wrote: >> >> This is an automated email from the ASF dual-hosted git repository. >> >> mattsicker pushed a commit to branch 2.x >> in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git >> >> >> The following commit(s) were added to refs/heads/2.x by this push: >> new 4243f7cfce Backport Lazy util >> 4243f7cfce is described below >> >> commit 4243f7cfceae535c898b863ada75417c0e4217fc >> Author: Matt Sicker <mattsic...@apache.org> >> AuthorDate: Fri Nov 3 18:18:10 2023 -0500 >> >> Backport Lazy util >> --- >> .../java/org/apache/logging/log4j/util/Lazy.java | 93 +++++++++++ >> .../org/apache/logging/log4j/util/LazyBoolean.java | 66 ++++++++ >> .../org/apache/logging/log4j/util/LazyUtil.java | 171 >> +++++++++++++++++++++ >> 3 files changed, 330 insertions(+) >> >> diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/Lazy.java >> b/log4j-api/src/main/java/org/apache/logging/log4j/util/Lazy.java >> new file mode 100644 >> index 0000000000..2e0d84b3ce >> --- /dev/null >> +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/Lazy.java >> @@ -0,0 +1,93 @@ >> +/* >> + * Licensed to the Apache Software Foundation (ASF) under one or more >> + * contributor license agreements. See the NOTICE file distributed with >> + * this work for additional information regarding copyright ownership. >> + * The ASF licenses this file to you under the Apache License, Version 2.0 >> + * (the "License"); you may not use this file except in compliance with >> + * the License. You may obtain a copy of the License at >> + * >> + * http://www.apache.org/licenses/LICENSE-2.0 >> + * >> + * Unless required by applicable law or agreed to in writing, software >> + * distributed under the License is distributed on an "AS IS" BASIS, >> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >> + * See the License for the specific language governing permissions and >> + * limitations under the License. >> + */ >> +package org.apache.logging.log4j.util; >> + >> +import java.util.Objects; >> +import java.util.function.Function; >> +import java.util.function.Supplier; >> + >> +/** >> + * Provides a lazily-initialized value from a {@code Supplier<T>}. >> + * >> + * @param <T> type of value >> + */ >> +public interface Lazy<T> extends Supplier<T> { >> + /** >> + * Returns the value held by this lazy. This may cause the value to >> initialize if it hasn't been already. >> + */ >> + T value(); >> + >> + /** >> + * Returns the value held by this lazy. This may cause the value to >> initialize if it hasn't been already. >> + */ >> + @Override >> + default T get() { >> + return value(); >> + } >> + >> + /** >> + * Creates a new lazy value derived from this lazy value using the >> provided value mapping function. >> + */ >> + default <R> Lazy<R> map(final Function<? super T, ? extends R> >> function) { >> + return lazy(() -> function.apply(value())); >> + } >> + >> + /** >> + * Indicates whether this lazy value has been initialized. >> + */ >> + boolean isInitialized(); >> + >> + /** >> + * Sets this lazy value to the provided value. >> + * >> + * @throws UnsupportedOperationException if this type of lazy value >> cannot be updated >> + */ >> + void set(final T newValue); >> + >> + /** >> + * Creates a strict lazy value using the provided Supplier. The >> supplier is guaranteed to only be invoked by at >> + * most one thread, and all threads will see the same published value >> when this returns. >> + */ >> + static <T> Lazy<T> lazy(final Supplier<T> supplier) { >> + Objects.requireNonNull(supplier); >> + return new LazyUtil.SafeLazy<>(supplier); >> + } >> + >> + /** >> + * Creates a lazy value using the provided constant value. >> + */ >> + static <T> Lazy<T> value(final T value) { >> + return new LazyUtil.Constant<>(value); >> + } >> + >> + /** >> + * Creates a lazy value using a weak reference to the provided value. >> + */ >> + static <T> Lazy<T> weak(final T value) { >> + return new LazyUtil.WeakConstant<>(value); >> + } >> + >> + /** >> + * Creates a pure lazy value using the provided Supplier to initialize >> the value. The supplier may be invoked more >> + * than once, and the return value should be a purely computed value as >> the result may be a different instance >> + * each time. This is useful for building cache tables and other pure >> computations. >> + */ >> + static <T> Lazy<T> pure(final Supplier<T> supplier) { >> + Objects.requireNonNull(supplier); >> + return new LazyUtil.PureLazy<>(supplier); >> + } >> +} >> diff --git >> a/log4j-api/src/main/java/org/apache/logging/log4j/util/LazyBoolean.java >> b/log4j-api/src/main/java/org/apache/logging/log4j/util/LazyBoolean.java >> new file mode 100644 >> index 0000000000..26db8639de >> --- /dev/null >> +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/LazyBoolean.java >> @@ -0,0 +1,66 @@ >> +/* >> + * Licensed to the Apache Software Foundation (ASF) under one or more >> + * contributor license agreements. See the NOTICE file distributed with >> + * this work for additional information regarding copyright ownership. >> + * The ASF licenses this file to you under the Apache License, Version 2.0 >> + * (the "License"); you may not use this file except in compliance with >> + * the License. You may obtain a copy of the License at >> + * >> + * http://www.apache.org/licenses/LICENSE-2.0 >> + * >> + * Unless required by applicable law or agreed to in writing, software >> + * distributed under the License is distributed on an "AS IS" BASIS, >> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >> + * See the License for the specific language governing permissions and >> + * limitations under the License. >> + */ >> +package org.apache.logging.log4j.util; >> + >> +import java.util.concurrent.locks.Lock; >> +import java.util.concurrent.locks.ReentrantLock; >> +import java.util.function.BooleanSupplier; >> + >> +public class LazyBoolean implements BooleanSupplier { >> + private final BooleanSupplier supplier; >> + private final Lock lock = new ReentrantLock(); >> + private volatile boolean initialized; >> + private volatile boolean value; >> + >> + public LazyBoolean(final BooleanSupplier supplier) { >> + this.supplier = supplier; >> + } >> + >> + @Override >> + public boolean getAsBoolean() { >> + boolean uninitialized = !initialized; >> + boolean value = this.value; >> + if (uninitialized) { >> + lock.lock(); >> + try { >> + uninitialized = !initialized; >> + if (uninitialized) { >> + this.value = value = supplier.getAsBoolean(); >> + initialized = true; >> + } >> + } finally { >> + lock.unlock(); >> + } >> + } >> + return value; >> + } >> + >> + public void setAsBoolean(final boolean b) { >> + lock.lock(); >> + try { >> + initialized = false; >> + value = b; >> + initialized = true; >> + } finally { >> + lock.unlock(); >> + } >> + } >> + >> + public void reset() { >> + initialized = false; >> + } >> +} >> diff --git >> a/log4j-api/src/main/java/org/apache/logging/log4j/util/LazyUtil.java >> b/log4j-api/src/main/java/org/apache/logging/log4j/util/LazyUtil.java >> new file mode 100644 >> index 0000000000..8b0b8c7a29 >> --- /dev/null >> +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/LazyUtil.java >> @@ -0,0 +1,171 @@ >> +/* >> + * Licensed to the Apache Software Foundation (ASF) under one or more >> + * contributor license agreements. See the NOTICE file distributed with >> + * this work for additional information regarding copyright ownership. >> + * The ASF licenses this file to you under the Apache License, Version 2.0 >> + * (the "License"); you may not use this file except in compliance with >> + * the License. You may obtain a copy of the License at >> + * >> + * http://www.apache.org/licenses/LICENSE-2.0 >> + * >> + * Unless required by applicable law or agreed to in writing, software >> + * distributed under the License is distributed on an "AS IS" BASIS, >> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >> + * See the License for the specific language governing permissions and >> + * limitations under the License. >> + */ >> +package org.apache.logging.log4j.util; >> + >> +import java.lang.ref.WeakReference; >> +import java.util.concurrent.locks.Lock; >> +import java.util.concurrent.locks.ReentrantLock; >> +import java.util.function.Supplier; >> + >> +final class LazyUtil { >> + private static final Object NULL = new Object() { >> + @Override >> + public String toString() { >> + return "null"; >> + } >> + }; >> + >> + static Object wrapNull(final Object value) { >> + return value == null ? NULL : value; >> + } >> + >> + static <T> T unwrapNull(final Object value) { >> + return value == NULL ? null : Cast.cast(value); >> + } >> + >> + static class Constant<T> implements Lazy<T> { >> + private final T value; >> + >> + Constant(final T value) { >> + this.value = value; >> + } >> + >> + @Override >> + public T value() { >> + return value; >> + } >> + >> + @Override >> + public boolean isInitialized() { >> + return true; >> + } >> + >> + @Override >> + public void set(final T newValue) { >> + throw new UnsupportedOperationException(); >> + } >> + >> + @Override >> + public String toString() { >> + return String.valueOf(value); >> + } >> + } >> + >> + static class WeakConstant<T> implements Lazy<T> { >> + private final WeakReference<T> reference; >> + >> + WeakConstant(final T value) { >> + reference = new WeakReference<>(value); >> + } >> + >> + @Override >> + public T value() { >> + return reference.get(); >> + } >> + >> + @Override >> + public boolean isInitialized() { >> + return true; >> + } >> + >> + @Override >> + public void set(final T newValue) { >> + throw new UnsupportedOperationException(); >> + } >> + >> + @Override >> + public String toString() { >> + return String.valueOf(value()); >> + } >> + } >> + >> + static class SafeLazy<T> implements Lazy<T> { >> + private final Lock lock = new ReentrantLock(); >> + private final Supplier<T> supplier; >> + private volatile Object value; >> + >> + SafeLazy(final Supplier<T> supplier) { >> + this.supplier = supplier; >> + } >> + >> + @Override >> + public T value() { >> + Object value = this.value; >> + if (value == null) { >> + lock.lock(); >> + try { >> + value = this.value; >> + if (value == null) { >> + value = supplier.get(); >> + this.value = wrapNull(value); >> + } >> + } finally { >> + lock.unlock(); >> + } >> + } >> + return unwrapNull(value); >> + } >> + >> + @Override >> + public void set(final T newValue) { >> + value = newValue; >> + } >> + >> + public void reset() { >> + value = null; >> + } >> + >> + @Override >> + public boolean isInitialized() { >> + return value != null; >> + } >> + >> + @Override >> + public String toString() { >> + return isInitialized() ? String.valueOf(value) : "Lazy value >> not initialized"; >> + } >> + } >> + >> + static class PureLazy<T> implements Lazy<T> { >> + private final Supplier<T> supplier; >> + private Object value; >> + >> + public PureLazy(final Supplier<T> supplier) { >> + this.supplier = supplier; >> + } >> + >> + @Override >> + public T value() { >> + Object value = this.value; >> + if (value == null) { >> + value = supplier.get(); >> + this.value = wrapNull(value); >> + } >> + return unwrapNull(value); >> + } >> + >> + @Override >> + public boolean isInitialized() { >> + return value != null; >> + } >> + >> + @Override >> + public void set(final T newValue) { >> + value = newValue; >> + } >> + } >> +} >> >