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

nstream.reflect.agent.MetaAgent Maven / Gradle / Ivy

The newest version!
// Copyright 2015-2024 Nstream, inc.
//
// Licensed under the Redis Source Available License 2.0 (RSALv2) Agreement;
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://redis.com/legal/rsalv2-agreement/
//
// 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 nstream.reflect.agent;

import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import nstream.reflect.Meta;
import nstream.reflect.model.LinkStats;
import nstream.reflect.model.LogEntry;
import swim.api.lane.DemandLane;
import swim.api.lane.SupplyLane;
import swim.api.lane.function.OnCue;
import swim.api.warp.WarpUplink;
import swim.concurrent.Cont;
import swim.structure.Value;
import swim.system.LinkBinding;
import swim.system.NodeContext;
import swim.system.agent.AgentNode;
import swim.uri.Uri;
import swim.warp.Envelope;

public abstract class MetaAgent extends AgentNode {
  protected final LinkStats linkTotal = new LinkStats();
  protected final LinkStats linkDelta = new LinkStats();

  volatile DemandLane linkStats;
  volatile SupplyLane traceLog;
  volatile SupplyLane debugLog;
  volatile SupplyLane infoLog;
  volatile SupplyLane warnLog;
  volatile SupplyLane errorLog;
  volatile SupplyLane failLog;

  volatile long bubbleTime;

  public MetaAgent() {
    // nop
  }

  public abstract Meta meta();

  @Override
  public void setNodeContext(NodeContext nodeContext) {
    super.setNodeContext(nodeContext);
    openLanes();
  }

  protected void openLanes() {
    final DemandLane linkStats = demandLane()
        .valueForm(LinkStats.form())
        .observe(new MetaLinkStatsController(this));
    openLane(LINK_STATS_URI, linkStats);
    this.linkStats = linkStats;

    final SupplyLane traceLog = supplyLane()
        .valueForm(LogEntry.form());
    openLane(TRACE_LOG_URI, traceLog);
    this.traceLog = traceLog;
    final SupplyLane debugLog = supplyLane()
        .valueForm(LogEntry.form());
    openLane(DEBUG_LOG_URI, debugLog);
    this.debugLog = debugLog;
    final SupplyLane infoLog = supplyLane()
        .valueForm(LogEntry.form());
    openLane(INFO_LOG_URI, infoLog);
    this.infoLog = infoLog;
    final SupplyLane warnLog = supplyLane()
        .valueForm(LogEntry.form());
    openLane(WARN_LOG_URI, warnLog);
    this.warnLog = warnLog;
    final SupplyLane errorLog = supplyLane()
        .valueForm(LogEntry.form());
    openLane(ERROR_LOG_URI, errorLog);
    this.errorLog = errorLog;
    final SupplyLane failLog = supplyLane()
        .valueForm(LogEntry.form());
    openLane(FAIL_LOG_URI, failLog);
    this.failLog = failLog;
  }

  public LinkStats linkStats() {
    return this.linkTotal.get();
  }

  public void didOpenDownlink(LinkBinding link) {
    this.linkTotal.didOpenDownlink(link);
    this.linkDelta.didOpenDownlink(link);
    didUpdateStats();
  }

  public void didCloseDownlink(LinkBinding link) {
    this.linkTotal.didCloseDownlink(link);
    this.linkDelta.didCloseDownlink(link);
    didUpdateStats();
  }

  public void didOpenUplink(LinkBinding link) {
    this.linkTotal.didOpenUplink(link);
    this.linkDelta.didOpenUplink(link);
    didUpdateStats();
  }

  public void didCloseUplink(Value linkKey) {
    this.linkTotal.didCloseUplink(linkKey);
    this.linkDelta.didCloseUplink(linkKey);
    didUpdateStats();
  }

  public void didPushDown(Envelope envelope) {
    this.linkTotal.didPushDown(envelope);
    this.linkDelta.didPushDown(envelope);
    didUpdateStats();
  }

  public void didPushUp(Envelope envelope) {
    this.linkTotal.didPushUp(envelope);
    this.linkDelta.didPushUp(envelope);
    didUpdateStats();
  }

  public void setLinkStats(LinkStats stats) {
    stats.supersede(this.linkTotal, this.linkDelta);
    didUpdateStats();
  }

  public void accumulateLinkStats(LinkStats stats) {
    this.linkTotal.accumulate(stats);
    this.linkDelta.accumulate(stats);
    didUpdateStats();
  }

  public void didUpdateStats() {
    do {
      final long oldBubbleTime = this.bubbleTime;
      final long newBubbleTime = System.currentTimeMillis();
      if (newBubbleTime - oldBubbleTime >= BUBBLE_INTERVAL) {
        if (BUBBLE_TIME.compareAndSet(this, oldBubbleTime, newBubbleTime)) {
          try {
            bubbleStats();
            cueStats();
          } catch (Throwable error) {
            if (Cont.isNonFatal(error)) {
              didFail(error);
            } else {
              throw error;
            }
          }
          break;
        }
      } else {
        break;
      }
    } while (true);
  }

  public void bubbleStats() {
    bubbleLinkStats();
  }

  protected void bubbleLinkStats() {
    final Meta metaParent = meta().metaParent();
    if (metaParent != null) {
      final MetaAgent parentAgent = metaParent.metaAgent();
      parentAgent.accumulateLinkStats(this.linkDelta.getAndReset());
    }
  }

  public void cueStats() {
    cueLinkStats();
  }

  protected void cueLinkStats() {
    final DemandLane linkStats = this.linkStats;
    if (linkStats != null) {
      linkStats.cue();
    }
  }

  public void didLogTrace(LogEntry entry) {
    try {
      final SupplyLane traceLog = this.traceLog;
      if (traceLog != null) {
        traceLog.push(entry);
      }
      bubbleTraceLog(entry);
    } catch (Throwable error) {
      if (Cont.isNonFatal(error)) {
        didFail(error);
      } else {
        throw error;
      }
    }
  }

  protected void bubbleTraceLog(LogEntry entry) {
    final Meta metaParent = meta().metaParent();
    if (metaParent != null) {
      final MetaAgent parentAgent = metaParent.metaAgent();
      parentAgent.didLogTrace(entry);
    }
  }

  public void didLogDebug(LogEntry entry) {
    try {
      final SupplyLane debugLog = this.debugLog;
      if (debugLog != null) {
        debugLog.push(entry);
      }
      bubbleDebugLog(entry);
    } catch (Throwable error) {
      if (Cont.isNonFatal(error)) {
        didFail(error);
      } else {
        throw error;
      }
    }
  }

  protected void bubbleDebugLog(LogEntry entry) {
    final Meta metaParent = meta().metaParent();
    if (metaParent != null) {
      final MetaAgent parentAgent = metaParent.metaAgent();
      parentAgent.didLogDebug(entry);
    }
  }

  public void didLogInfo(LogEntry entry) {
    try {
      final SupplyLane infoLog = this.infoLog;
      if (infoLog != null) {
        infoLog.push(entry);
      }
      bubbleInfoLog(entry);
    } catch (Throwable error) {
      if (Cont.isNonFatal(error)) {
        didFail(error);
      } else {
        throw error;
      }
    }
  }

  protected void bubbleInfoLog(LogEntry entry) {
    final Meta metaParent = meta().metaParent();
    if (metaParent != null) {
      final MetaAgent parentAgent = metaParent.metaAgent();
      parentAgent.didLogInfo(entry);
    }
  }

  public void didLogWarn(LogEntry entry) {
    try {
      final SupplyLane warnLog = this.warnLog;
      if (warnLog != null) {
        warnLog.push(entry);
      }
      bubbleWarnLog(entry);
    } catch (Throwable error) {
      if (Cont.isNonFatal(error)) {
        didFail(error);
      } else {
        throw error;
      }
    }
  }

  protected void bubbleWarnLog(LogEntry entry) {
    final Meta metaParent = meta().metaParent();
    if (metaParent != null) {
      final MetaAgent parentAgent = metaParent.metaAgent();
      parentAgent.didLogWarn(entry);
    }
  }

  public void didLogError(LogEntry entry) {
    try {
      final SupplyLane errorLog = this.errorLog;
      if (errorLog != null) {
        errorLog.push(entry);
      }
      bubbleErrorLog(entry);
    } catch (Throwable error) {
      if (Cont.isNonFatal(error)) {
        didFail(error);
      } else {
        throw error;
      }
    }
  }

  protected void bubbleErrorLog(LogEntry entry) {
    final Meta metaParent = meta().metaParent();
    if (metaParent != null) {
      final MetaAgent parentAgent = metaParent.metaAgent();
      parentAgent.didLogError(entry);
    }
  }

  public void didLogFail(LogEntry entry) {
    try {
      final SupplyLane failLog = this.failLog;
      if (failLog != null) {
        failLog.push(entry);
      }
      bubbleFailLog(entry);
    } catch (Throwable error) {
      if (Cont.isNonFatal(error)) {
        didFail(error);
      } else {
        throw error;
      }
    }
  }

  protected void bubbleFailLog(LogEntry entry) {
    final Meta metaParent = meta().metaParent();
    if (metaParent != null) {
      final MetaAgent parentAgent = metaParent.metaAgent();
      parentAgent.didLogFail(entry);
    }
  }

  @Override
  public void close() {
    super.close();
    bubbleStats();
  }

  static final Uri LINK_STATS_URI = Uri.parse("linkStats");
  static final Uri TRACE_LOG_URI = Uri.parse("traceLog");
  static final Uri DEBUG_LOG_URI = Uri.parse("debugLog");
  static final Uri INFO_LOG_URI = Uri.parse("infoLog");
  static final Uri WARN_LOG_URI = Uri.parse("warnLog");
  static final Uri ERROR_LOG_URI = Uri.parse("errorLog");
  static final Uri FAIL_LOG_URI = Uri.parse("failLog");
  static final long BUBBLE_INTERVAL = 1000L;

  static final AtomicLongFieldUpdater BUBBLE_TIME =
      AtomicLongFieldUpdater.newUpdater(MetaAgent.class, "bubbleTime");
}

final class MetaLinkStatsController implements OnCue {
  final MetaAgent agent;

  MetaLinkStatsController(MetaAgent agent) {
    this.agent = agent;
  }

  @Override
  public LinkStats onCue(WarpUplink uplink) {
    return this.agent.linkStats();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy