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

nstream.reflect.model.NodeStats 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.model;

import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import swim.collections.HashTrieMap;
import swim.structure.Form;
import swim.structure.Item;
import swim.structure.Kind;
import swim.structure.Record;
import swim.structure.Value;
import swim.uri.Uri;

@SuppressWarnings("checkstyle:VisibilityModifier")
public class NodeStats {
  public final Value nodeKey;
  public volatile long nodeCount;
  public volatile HashTrieMap laneStats;

  public NodeStats(Value nodeKey, long nodeCount, HashTrieMap laneStats) {
    this.nodeKey = nodeKey;
    this.nodeCount = nodeCount;
    this.laneStats = laneStats;
  }

  public NodeStats(Value nodeKey, HashTrieMap laneStats) {
    this(nodeKey, 0L, laneStats);
  }

  public NodeStats(Value nodeKey) {
    this(nodeKey, 0L, HashTrieMap.empty());
  }

  public void didOpenNode() {
    NODE_COUNT.incrementAndGet(this);
  }

  public void didCloseNode() {
    NODE_COUNT.decrementAndGet(this);
  }

  public LaneStats getOrCreateLaneStats(Uri laneUri) {
    LaneStats lane;
    do {
      final HashTrieMap oldLaneStats = this.laneStats;
      lane = oldLaneStats.get(laneUri);
      if (lane == null) {
        lane = new LaneStats(laneUri);
        final HashTrieMap newLaneStats = oldLaneStats.updated(laneUri, lane);
        if (LANE_STATS.compareAndSet(this, oldLaneStats, newLaneStats)) {
          break;
        }
      } else {
        break;
      }
    } while (true);
    return lane;
  }

  public void accumulate(NodeStats node) {
    NODE_COUNT.addAndGet(this, node.nodeCount);
    for (LaneStats lane : this.laneStats.values()) {
      accumulate(lane);
    }
  }

  public void accumulate(LaneStats stats) {
    final LaneStats lane = getOrCreateLaneStats(stats.laneUri);
    lane.accumulate(stats);
  }

  public void supersede(NodeStats total, NodeStats delta) {
    final long newNodeCount = this.nodeCount;
    final long oldNodeCount = NODE_COUNT.getAndSet(total, newNodeCount);
    NODE_COUNT.addAndGet(delta, newNodeCount - oldNodeCount);

    for (LaneStats lane : this.laneStats.values()) {
      final LaneStats laneTotal = total.getOrCreateLaneStats(lane.laneUri);
      final LaneStats laneDelta = delta.getOrCreateLaneStats(lane.laneUri);
      lane.supersede(laneTotal, laneDelta);
    }
  }

  public NodeStats getAndReset() {
    final long nodeCount = NODE_COUNT.getAndSet(this, 0L);

    final HashTrieMap oldLaneStats = this.laneStats;
    HashTrieMap newLaneStats = HashTrieMap.empty();
    for (LaneStats lane : oldLaneStats.values()) {
      newLaneStats = newLaneStats.updated(lane.laneUri, lane.getAndReset());
    }

    return new NodeStats(nodeKey, nodeCount, newLaneStats);
  }

  public NodeStats get() {
    final long nodeCount = this.nodeCount;

    final HashTrieMap oldLaneStats = this.laneStats;
    HashTrieMap newLaneStats = HashTrieMap.empty();
    for (LaneStats lane : oldLaneStats.values()) {
      newLaneStats = newLaneStats.updated(lane.laneUri, lane.get());
    }

    return new NodeStats(nodeKey, nodeCount, newLaneStats);
  }

  public Value toValue() {
    return form().mold(this).toValue();
  }

  static final AtomicLongFieldUpdater NODE_COUNT =
      AtomicLongFieldUpdater.newUpdater(NodeStats.class, "nodeCount");

  @SuppressWarnings("unchecked")
  static final AtomicReferenceFieldUpdater> LANE_STATS =
      AtomicReferenceFieldUpdater.newUpdater(NodeStats.class, (Class>) (Class) HashTrieMap.class, "laneStats");

  private static Form form;

  @Kind
  public static Form form() {
    if (form == null) {
      form = new NodeStatsForm();
    }
    return form;
  }
}

final class NodeStatsForm extends Form {
  @Override
  public String tag() {
    return "node";
  }

  @Override
  public Class type() {
    return NodeStats.class;
  }

  @Override
  public Item mold(NodeStats stats) {
    if (stats != null) {
      final Record record = Record.create();
      record.attr(tag(), stats.nodeKey);
      if (stats.nodeCount > 0L) {
        record.slot("nodeCount", stats.nodeCount);
      }
      for (LaneStats lane : stats.laneStats.values()) {
        record.item(lane.toValue());
      }
      return record;
    } else {
      return Item.extant();
    }
  }

  @Override
  public NodeStats cast(Item item) {
    final Value value = item.toValue();
    final Value nodeKey = value.getAttr(tag());
    if (nodeKey.isDefined()) {
      long nodeCount = 0L;

      HashTrieMap laneStats = HashTrieMap.empty();
      for (Item member : value) {
        if ("nodeCount".equals(member.key().stringValue())) {
          nodeCount = member.toValue().longValue(0L);
          continue;
        }
        final LaneStats lane = LaneStats.form().cast(member);
        if (lane != null) {
          laneStats = laneStats.updated(lane.laneUri, lane);
        }
      }

      return new NodeStats(nodeKey, nodeCount, laneStats);
    }
    return null;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy