All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.spf4j.base.ExecutionContext Maven / Gradle / Ivy

Go to download

A continuously growing collection of utilities to measure performance, get better diagnostics, improve performance, or do things more reliably, faster that other open source libraries...

There is a newer version: 8.10.0
Show newest version
/*
 * Copyright (c) 2001-2017, Zoltan Farkas All Rights Reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * Additionally licensed with:
 *
 * Licensed 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.spf4j.base;

import com.google.common.annotations.Beta;
import edu.umd.cs.findbugs.annotations.CleanupObligation;
import edu.umd.cs.findbugs.annotations.DischargesObligation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import javax.annotation.Signed;
import org.spf4j.base.avro.Converters;
import org.spf4j.base.avro.DebugDetail;
import org.spf4j.base.avro.StackSampleElement;
import org.spf4j.log.Level;
import org.spf4j.log.Slf4jLogRecord;

/**
 * Execution context information encapsulated a place to store execution related information:
 * 
    *
  • deadline/timeout
  • *
  • context logs/overrides
  • *
  • tagged attachments (profiling info, etc..)
  • *
* @author Zoltan Farkas */ @CleanupObligation @ParametersAreNonnullByDefault public interface ExecutionContext extends AutoCloseable, JsonWriteable { public interface SimpleTag extends Tag { } public interface Tag { String toString(); /** * if true, a child execution context will check parent execution contexts * for tag values if not local values exist. */ default boolean isInherited(final Relation relation) { return true; } /** * push this tag/values to the parent context when current context is closed. * only child -> parent will be pushed, follows relationships will not be considered. */ default boolean pushOnClose() { return false; } default T accumulate(@Nullable final T existing, final T newVal) { return newVal; } default T accumulateComponent(@Nullable final T existing, final A component) { throw new UnsupportedOperationException(); } } enum Relation { CHILD_OF, FOLLOWS } @DischargesObligation void close(); @Nonnull String getName(); CharSequence getId(); long getStartTimeNanos(); long getDeadlineNanos(); @Nullable ExecutionContext getSource(); /** * @return the top source. will return this is current is root. * will follow all relationship types. */ default ExecutionContext getRoot() { ExecutionContext curr = this; ExecutionContext parent; while ((parent = curr.getSource()) != null) { curr = parent; } return curr; } /** * @return Adam of this current context. will return this is current is Adam. * follows only CHILD_OF relationships. */ default ExecutionContext getRootParent() { ExecutionContext curr = this; ExecutionContext parent; while (curr.getRelationToSource() == Relation.CHILD_OF && (parent = curr.getSource()) != null) { curr = parent; } return curr; } /** * @return will return the first not closed parent. null if no parent is available. */ @Nullable default ExecutionContext getNotClosedParent() { ExecutionContext curr = this; ExecutionContext parent; do { if (curr.getRelationToSource() != Relation.CHILD_OF) { return null; } parent = curr.getSource(); if (parent == null || !parent.isClosed()) { break; } curr = parent; } while (true); return parent; } @Beta void addLog(Slf4jLogRecord log); @Beta void addLogs(Collection log); /** * Attach a AutoCloseable to execution context. * All of them will be closed when context is closed, in reverse registration order. * @param closeable */ @Beta void addCloseable(AutoCloseable closeable); /** * The minimum log level accepted by this execution context; * The logs that we will store in this context. * @return */ @Beta Level getContextMinLogLevel(String loggerName); default Level getContextMinLogLevel() { return getContextMinLogLevel(""); } /** * The minimum log level overwrite. * An execution context can overwrite the backend configured log level. * @return null if not specified. */ @Beta @Nullable Level getBackendMinLogLevel(String loggerName); @Nullable default Level getBackendMinLogLevel() { return getBackendMinLogLevel(""); } @Beta @Nullable Level setBackendMinLogLevel(String loggerName, Level level); @Nullable default Level setBackendMinLogLevel(Level level) { return setBackendMinLogLevel("", level); } @Beta void streamLogs(Consumer to); @Beta void streamLogs(Consumer to, int nrLogs); /** * Detach this execution context from the current Thread. */ void detach(); /** * Attach execution context to the current thread. * A thread will typically have a stack of execution contexts attached to it. */ void attach(); /** * @return true if execution context is attached to a thread or not. */ boolean isAttached(); @Nonnegative default long getTimeToDeadline(final TimeUnit unit) throws TimeoutException { long result = getTimeRelativeToDeadline(unit); if (result <= 0) { throw new TimeoutException("Deadline exceeded by " + (-result) + ' ' + unit); } return result; } @Nonnegative default long getUncheckedTimeToDeadline(final TimeUnit unit) { long result = getTimeRelativeToDeadline(unit); if (result <= 0) { throw new UncheckedTimeoutException("Deadline exceeded by " + (-result) + ' ' + unit); } return result; } @Signed default long getTimeRelativeToDeadline(final TimeUnit unit) { return unit.convert(getDeadlineNanos() - TimeSource.nanoTime(), TimeUnit.NANOSECONDS); } @Nonnegative default long getMillisToDeadline() throws TimeoutException { return getTimeToDeadline(TimeUnit.MILLISECONDS); } @Nonnegative default int getSecondsToDeadline() throws TimeoutException { long secondsToDeadline = getTimeToDeadline(TimeUnit.SECONDS); if (secondsToDeadline > Integer.MAX_VALUE) { return Integer.MAX_VALUE; } else { return (int) secondsToDeadline; } } /** * Method to get context associated data. * if current context does not have baggage, the parent context is queried if tag is inherited. * This is done recursively. * @param type of data. * @param key key of data. * @return the data */ @Nullable @Beta T get(Tag key); /** * Method to get context associated data. * if current context does not have baggage, the parent context is queried if tag is inherited. * This is done recursively, and both the context and the value are returned. * @param type of data. * @param key key of data. * @return the data */ @Nullable @Beta ContextValue getContextAndValue(Tag key); /** * Method to get context associated data. * will ignore inheritance tag attribute. * @param type of data. * @param key key of data. * @return the data */ @Nullable @Beta T getLocal(Tag key); /** * Method to put context associated data. * @param type of data. * @param key the key of data. * @param data the data. * @return existing data if there. */ @Nullable @Beta T put(Tag tag, T data); /** * @deprecated use accumulate. */ @Deprecated default void combine(Tag tag, T data) { accumulate(tag, data); } @Beta default void accumulate(Tag tag, T data) { compute(tag, (t, v) -> t.accumulate(v, data)); } @Beta default void accumulateComponent(Tag tag, A data) { compute(tag, (t, v) -> t.accumulateComponent(v, data)); } /** * Method to put context associated data to the root context. * @param type of data. * @param key the key of data. * @param data the data. * @return existing data if there. */ @Nullable @Beta default T putToRootParent(final Tag key, final T data) { return getRootParent().put(key, data); } /** * Compute context associated data. * @param * @param * @param key * @param compute * @return */ @Beta @Nullable V compute(Tag key, BiFunction, V, V> compute); @Nullable @Beta default List addToRootParent(final Tag, T> tag, final T data) { ExecutionContext ctx = getRootParent(); return ctx.compute(tag, (k, v) -> { if (v == null) { v = new ArrayList<>(2); } v.add(data); return v; }); } default ExecutionContext startChild(final String operationName, final long timeout, final TimeUnit tu) { return ExecutionContexts.start(operationName, this, timeout, tu); } default ExecutionContext startChild(final String operationName) { return ExecutionContexts.start(operationName, this); } default ExecutionContext detachedChild(final String operationName, final long timeout, final TimeUnit tu) { return ExecutionContexts.createDetached(operationName, this, timeout, tu); } default ExecutionContext detachedChild(final String operationName) { return ExecutionContexts.createDetached(operationName, this, TimeSource.nanoTime(), this.getDeadlineNanos()); } long nextChildId(); void add(StackTraceElement[] sample); void add(StackSamples samples); @Nullable StackSamples getAndClearStackSamples(); @Nullable StackSamples getStackSamples(); boolean isClosed(); Relation getRelationToSource(); default DebugDetail getDebugDetail(final String origin, @Nullable final Throwable throwable) { return getDebugDetail(origin, throwable, true); } default DebugDetail getDebugDetail(final String origin, @Nullable final Throwable throwable, boolean addStackSamples) { return getDebugDetail(origin, throwable, addStackSamples, 100); } default DebugDetail getDebugDetail(final String origin, @Nullable final Throwable throwable, boolean addStackSamples, final int maxNrLogs) { List ctxLogs = new ArrayList<>(); ExecutionContext curr = this; while (curr != null) { curr.streamLogs((log) -> { ctxLogs.add(log); }, maxNrLogs); curr = curr.getSource(); } Collections.sort(ctxLogs, Slf4jLogRecord::compareByTimestamp); if (addStackSamples) { StackSamples ss = this.getAndClearStackSamples(); List sses = Converters.convert(ss); return new DebugDetail(origin + '/' + this.getName(), Converters.convert("", this.getId().toString(), ctxLogs), throwable == null ? null : Converters.convert(throwable), sses); } else { return new DebugDetail(origin + '/' + this.getName(), Converters.convert("", this.getId().toString(), ctxLogs), throwable == null ? null : Converters.convert(throwable), Collections.emptyList()); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy