swim.system.warp.WarpLaneModel Maven / Gradle / Ivy
The newest version!
// Copyright 2015-2024 Nstream, inc.
//
// 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 swim.system.warp;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import swim.api.LaneException;
import swim.api.auth.Identity;
import swim.api.warp.WarpUplink;
import swim.collections.FingerTrieSeq;
import swim.concurrent.Cont;
import swim.structure.Value;
import swim.system.LaneModel;
import swim.system.LaneRelay;
import swim.system.LinkBinding;
import swim.system.Metric;
import swim.system.Push;
import swim.system.WarpBinding;
import swim.system.profile.WarpDownlinkProfile;
import swim.system.profile.WarpLaneProfile;
import swim.system.profile.WarpUplinkProfile;
import swim.warp.CommandMessage;
public abstract class WarpLaneModel extends LaneModel {
volatile long execDelta;
volatile long execTime;
volatile int commandDelta;
volatile int downlinkOpenDelta;
volatile int downlinkOpenCount;
volatile int downlinkCloseDelta;
volatile int downlinkCloseCount;
volatile long downlinkExecDelta;
volatile long downlinkExecRate;
volatile int downlinkEventDelta;
volatile int downlinkEventRate;
volatile long downlinkEventCount;
volatile int downlinkCommandDelta;
volatile int downlinkCommandRate;
volatile long downlinkCommandCount;
volatile int uplinkOpenDelta;
volatile int uplinkOpenCount;
volatile int uplinkCloseDelta;
volatile int uplinkCloseCount;
volatile int uplinkEventDelta;
volatile int uplinkEventRate;
volatile long uplinkEventCount;
volatile int uplinkCommandDelta;
volatile int uplinkCommandRate;
volatile long uplinkCommandCount;
volatile long lastReportTime;
public WarpLaneModel() {
this.execDelta = 0L;
this.execTime = 0L;
this.commandDelta = 0;
this.downlinkOpenDelta = 0;
this.downlinkOpenCount = 0;
this.downlinkCloseDelta = 0;
this.downlinkCloseCount = 0;
this.downlinkExecDelta = 0L;
this.downlinkExecRate = 0L;
this.downlinkEventDelta = 0;
this.downlinkEventRate = 0;
this.downlinkEventCount = 0L;
this.downlinkCommandDelta = 0;
this.downlinkCommandRate = 0;
this.downlinkCommandCount = 0L;
this.uplinkOpenDelta = 0;
this.uplinkOpenCount = 0;
this.uplinkCloseDelta = 0;
this.uplinkCloseCount = 0;
this.uplinkEventDelta = 0;
this.uplinkEventRate = 0;
this.uplinkEventCount = 0L;
this.uplinkCommandDelta = 0;
this.uplinkCommandRate = 0;
this.uplinkCommandCount = 0L;
this.lastReportTime = 0L;
}
@Override
protected U createUplink(LinkBinding link) {
if (link instanceof WarpBinding) {
return this.createWarpUplink((WarpBinding) link);
}
return null;
}
protected abstract U createWarpUplink(WarpBinding link);
@SuppressWarnings("unchecked")
public void cueDown() {
FingerTrieSeq uplinks;
FingerTrieSeq closedLinks = FingerTrieSeq.empty();
do {
uplinks = (FingerTrieSeq) (FingerTrieSeq>) LaneModel.UPLINKS.get(this);
for (int i = 0, n = uplinks.size(); i < n; i += 1) {
final U uplink = uplinks.get(i);
if (uplink.isConnected()) {
uplink.cueDown();
} else {
closedLinks = closedLinks.appended(uplink.linkKey());
}
}
} while (uplinks != LaneModel.UPLINKS.get(this));
for (Value linkKey : closedLinks) {
this.closeUplink(linkKey);
}
}
@SuppressWarnings("unchecked")
public void sendDown(Value body) {
FingerTrieSeq uplinks;
FingerTrieSeq closedLinks = FingerTrieSeq.empty();
do {
uplinks = (FingerTrieSeq) (FingerTrieSeq>) LaneModel.UPLINKS.get(this);
for (int i = 0, n = uplinks.size(); i < n; i += 1) {
final U uplink = uplinks.get(i);
if (uplink.isConnected()) {
uplink.sendDown(body);
} else {
closedLinks = closedLinks.appended(uplink.linkKey());
}
}
} while (uplinks != LaneModel.UPLINKS.get(this));
for (Value linkKey : closedLinks) {
this.closeUplink(linkKey);
}
}
@SuppressWarnings("unchecked")
@Override
public void pushUp(Push> push) {
final Object message = push.message();
if (message instanceof CommandMessage) {
this.onCommand((Push) push);
} else {
push.trap(new LaneException("unsupported message: " + message));
}
}
@Override
public void pushUpCommand(Push push) {
this.onCommand(push);
WarpLaneModel.COMMAND_DELTA.incrementAndGet(this);
this.didUpdateMetrics();
}
protected void onCommand(Push push) {
new WarpLaneRelayOnCommand(this, push.message(), push.cont()).run();
}
@Override
protected void didOpenUplink(U uplink) {
new WarpLaneRelayDidUplink(this, uplink).run();
WarpLaneModel.UPLINK_OPEN_DELTA.incrementAndGet(this);
this.flushMetrics();
}
@Override
protected void didCloseUplink(U uplink) {
WarpLaneModel.UPLINK_CLOSE_DELTA.incrementAndGet(this);
this.flushMetrics();
}
protected void didEnter(Identity identity) {
new WarpLaneRelayDidEnter(this, identity).run();
}
protected void didLeave(Identity identity) {
new WarpLaneRelayDidLeave(this, identity).run();
}
@Override
public void didClose() {
super.didClose();
this.flushMetrics();
}
@Override
public void reportDown(Metric metric) {
if (metric instanceof WarpUplinkProfile) {
this.accumulateWarpUplinkProfile((WarpUplinkProfile) metric);
} else if (metric instanceof WarpDownlinkProfile) {
this.accumulateWarpDownlinkProfile((WarpDownlinkProfile) metric);
} else {
super.reportDown(metric);
}
}
@Override
public void accumulateExecTime(long execDelta) {
WarpLaneModel.EXEC_DELTA.addAndGet(this, execDelta);
this.didUpdateMetrics();
}
protected void accumulateWarpUplinkProfile(WarpUplinkProfile profile) {
WarpLaneModel.UPLINK_EVENT_DELTA.addAndGet(this, profile.eventDelta());
WarpLaneModel.UPLINK_EVENT_RATE.addAndGet(this, profile.eventRate());
WarpLaneModel.UPLINK_COMMAND_DELTA.addAndGet(this, profile.commandDelta());
WarpLaneModel.UPLINK_COMMAND_RATE.addAndGet(this, profile.commandRate());
this.didUpdateMetrics();
}
protected void accumulateWarpDownlinkProfile(WarpDownlinkProfile profile) {
WarpLaneModel.DOWNLINK_OPEN_DELTA.addAndGet(this, profile.openDelta());
WarpLaneModel.DOWNLINK_CLOSE_DELTA.addAndGet(this, profile.closeDelta());
WarpLaneModel.DOWNLINK_EXEC_DELTA.addAndGet(this, profile.execDelta());
WarpLaneModel.DOWNLINK_EXEC_RATE.addAndGet(this, profile.execRate());
WarpLaneModel.DOWNLINK_EVENT_DELTA.addAndGet(this, profile.eventDelta());
WarpLaneModel.DOWNLINK_EVENT_RATE.addAndGet(this, profile.eventRate());
WarpLaneModel.DOWNLINK_COMMAND_DELTA.addAndGet(this, profile.commandDelta());
WarpLaneModel.DOWNLINK_COMMAND_RATE.addAndGet(this, profile.commandRate());
this.didUpdateMetrics();
}
protected void didUpdateMetrics() {
do {
final long oldReportTime = WarpLaneModel.LAST_REPORT_TIME.get(this);
final long newReportTime = System.currentTimeMillis();
final long dt = newReportTime - oldReportTime;
if (dt >= Metric.REPORT_INTERVAL) {
if (WarpLaneModel.LAST_REPORT_TIME.compareAndSet(this, oldReportTime, newReportTime)) {
try {
this.reportMetrics(dt);
} catch (Throwable error) {
if (Cont.isNonFatal(error)) {
this.didFail(error);
} else {
throw error;
}
}
break;
}
} else {
break;
}
} while (true);
}
protected void flushMetrics() {
final long newReportTime = System.currentTimeMillis();
final long oldReportTime = WarpLaneModel.LAST_REPORT_TIME.getAndSet(this, newReportTime);
final long dt = newReportTime - oldReportTime;
try {
this.reportMetrics(dt);
} catch (Throwable error) {
if (Cont.isNonFatal(error)) {
this.didFail(error);
} else {
throw error;
}
}
}
protected void reportMetrics(long dt) {
final WarpLaneProfile profile = this.collectProfile(dt);
this.laneContext.reportDown(profile);
}
protected WarpLaneProfile collectProfile(long dt) {
final int commandDelta = WarpLaneModel.COMMAND_DELTA.getAndSet(this, 0);
final int commandRate = (int) Math.ceil((1000.0 * (double) commandDelta) / (double) dt);
final int downlinkOpenDelta = WarpLaneModel.DOWNLINK_OPEN_DELTA.getAndSet(this, 0);
final int downlinkOpenCount = WarpLaneModel.DOWNLINK_OPEN_COUNT.addAndGet(this, downlinkOpenDelta);
final int downlinkCloseDelta = WarpLaneModel.DOWNLINK_CLOSE_DELTA.getAndSet(this, 0);
final int downlinkCloseCount = WarpLaneModel.DOWNLINK_CLOSE_COUNT.addAndGet(this, downlinkCloseDelta);
final long downlinkExecDelta = WarpLaneModel.DOWNLINK_EXEC_DELTA.getAndSet(this, 0L);
final long downlinkExecRate = WarpLaneModel.DOWNLINK_EXEC_RATE.getAndSet(this, 0L);
final int downlinkEventDelta = WarpLaneModel.DOWNLINK_EVENT_DELTA.getAndSet(this, 0);
final int downlinkEventRate = WarpLaneModel.DOWNLINK_EVENT_RATE.getAndSet(this, 0);
final long downlinkEventCount = WarpLaneModel.DOWNLINK_EVENT_COUNT.addAndGet(this, (long) downlinkEventDelta);
final int downlinkCommandDelta = WarpLaneModel.DOWNLINK_COMMAND_DELTA.getAndSet(this, 0);
final int downlinkCommandRate = WarpLaneModel.DOWNLINK_COMMAND_RATE.getAndSet(this, 0);
final long downlinkCommandCount = WarpLaneModel.DOWNLINK_COMMAND_COUNT.addAndGet(this, (long) downlinkCommandDelta);
final int uplinkOpenDelta = WarpLaneModel.UPLINK_OPEN_DELTA.getAndSet(this, 0);
final int uplinkOpenCount = WarpLaneModel.UPLINK_OPEN_COUNT.addAndGet(this, uplinkOpenDelta);
final int uplinkCloseDelta = WarpLaneModel.UPLINK_CLOSE_DELTA.getAndSet(this, 0);
final int uplinkCloseCount = WarpLaneModel.UPLINK_CLOSE_COUNT.addAndGet(this, uplinkCloseDelta);
final int uplinkEventDelta = WarpLaneModel.UPLINK_EVENT_DELTA.getAndSet(this, 0);
final int uplinkEventRate = WarpLaneModel.UPLINK_EVENT_RATE.getAndSet(this, 0);
final long uplinkEventCount = WarpLaneModel.UPLINK_EVENT_COUNT.addAndGet(this, (long) uplinkEventDelta);
final int uplinkCommandDelta = WarpLaneModel.UPLINK_COMMAND_DELTA.getAndSet(this, 0) + commandDelta;
final int uplinkCommandRate = WarpLaneModel.UPLINK_COMMAND_RATE.getAndSet(this, 0) + commandRate;
final long uplinkCommandCount = WarpLaneModel.UPLINK_COMMAND_COUNT.addAndGet(this, (long) uplinkCommandDelta);
final long execDelta = WarpLaneModel.EXEC_DELTA.getAndSet(this, 0L) + downlinkExecDelta;
final long execRate = (long) Math.ceil((1000.0 * (double) execDelta) / (double) dt) + downlinkExecRate;
final long execTime = WarpLaneModel.EXEC_TIME.addAndGet(this, execDelta);
return new WarpLaneProfile(this.cellAddress(), execDelta, execRate, execTime,
downlinkOpenDelta, downlinkOpenCount, downlinkCloseDelta, downlinkCloseCount,
downlinkEventDelta, downlinkEventRate, downlinkEventCount,
downlinkCommandDelta, downlinkCommandRate, downlinkCommandCount,
uplinkOpenDelta, uplinkOpenCount, uplinkCloseDelta, uplinkCloseCount,
uplinkEventDelta, uplinkEventRate, uplinkEventCount,
uplinkCommandDelta, uplinkCommandRate, uplinkCommandCount);
}
@SuppressWarnings("unchecked")
protected static final AtomicLongFieldUpdater> EXEC_DELTA =
AtomicLongFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "execDelta");
@SuppressWarnings("unchecked")
protected static final AtomicLongFieldUpdater> EXEC_TIME =
AtomicLongFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "execTime");
@SuppressWarnings("unchecked")
static final AtomicIntegerFieldUpdater> COMMAND_DELTA =
AtomicIntegerFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "commandDelta");
@SuppressWarnings("unchecked")
static final AtomicIntegerFieldUpdater> DOWNLINK_OPEN_DELTA =
AtomicIntegerFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "downlinkOpenDelta");
@SuppressWarnings("unchecked")
static final AtomicIntegerFieldUpdater> DOWNLINK_OPEN_COUNT =
AtomicIntegerFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "downlinkOpenCount");
@SuppressWarnings("unchecked")
static final AtomicIntegerFieldUpdater> DOWNLINK_CLOSE_DELTA =
AtomicIntegerFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "downlinkCloseDelta");
@SuppressWarnings("unchecked")
static final AtomicIntegerFieldUpdater> DOWNLINK_CLOSE_COUNT =
AtomicIntegerFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "downlinkCloseCount");
@SuppressWarnings("unchecked")
static final AtomicLongFieldUpdater> DOWNLINK_EXEC_DELTA =
AtomicLongFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "downlinkExecDelta");
@SuppressWarnings("unchecked")
static final AtomicLongFieldUpdater> DOWNLINK_EXEC_RATE =
AtomicLongFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "downlinkExecRate");
@SuppressWarnings("unchecked")
static final AtomicIntegerFieldUpdater> DOWNLINK_EVENT_DELTA =
AtomicIntegerFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "downlinkEventDelta");
@SuppressWarnings("unchecked")
static final AtomicIntegerFieldUpdater> DOWNLINK_EVENT_RATE =
AtomicIntegerFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "downlinkEventRate");
@SuppressWarnings("unchecked")
static final AtomicLongFieldUpdater> DOWNLINK_EVENT_COUNT =
AtomicLongFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "downlinkEventCount");
@SuppressWarnings("unchecked")
static final AtomicIntegerFieldUpdater> DOWNLINK_COMMAND_DELTA =
AtomicIntegerFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "downlinkCommandDelta");
@SuppressWarnings("unchecked")
static final AtomicIntegerFieldUpdater> DOWNLINK_COMMAND_RATE =
AtomicIntegerFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "downlinkCommandRate");
@SuppressWarnings("unchecked")
static final AtomicLongFieldUpdater> DOWNLINK_COMMAND_COUNT =
AtomicLongFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "downlinkCommandCount");
@SuppressWarnings("unchecked")
static final AtomicIntegerFieldUpdater> UPLINK_OPEN_DELTA =
AtomicIntegerFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "uplinkOpenDelta");
@SuppressWarnings("unchecked")
static final AtomicIntegerFieldUpdater> UPLINK_OPEN_COUNT =
AtomicIntegerFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "uplinkOpenCount");
@SuppressWarnings("unchecked")
static final AtomicIntegerFieldUpdater> UPLINK_CLOSE_DELTA =
AtomicIntegerFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "uplinkCloseDelta");
@SuppressWarnings("unchecked")
static final AtomicIntegerFieldUpdater> UPLINK_CLOSE_COUNT =
AtomicIntegerFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "uplinkCloseCount");
@SuppressWarnings("unchecked")
static final AtomicIntegerFieldUpdater> UPLINK_EVENT_DELTA =
AtomicIntegerFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "uplinkEventDelta");
@SuppressWarnings("unchecked")
static final AtomicIntegerFieldUpdater> UPLINK_EVENT_RATE =
AtomicIntegerFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "uplinkEventRate");
@SuppressWarnings("unchecked")
static final AtomicLongFieldUpdater> UPLINK_EVENT_COUNT =
AtomicLongFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "uplinkEventCount");
@SuppressWarnings("unchecked")
static final AtomicIntegerFieldUpdater> UPLINK_COMMAND_DELTA =
AtomicIntegerFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "uplinkCommandDelta");
@SuppressWarnings("unchecked")
static final AtomicIntegerFieldUpdater> UPLINK_COMMAND_RATE =
AtomicIntegerFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "uplinkCommandRate");
@SuppressWarnings("unchecked")
static final AtomicLongFieldUpdater> UPLINK_COMMAND_COUNT =
AtomicLongFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "uplinkCommandCount");
@SuppressWarnings("unchecked")
static final AtomicLongFieldUpdater> LAST_REPORT_TIME =
AtomicLongFieldUpdater.newUpdater((Class>) (Class>) WarpLaneModel.class, "lastReportTime");
}
final class WarpLaneRelayOnCommand extends LaneRelay, View> {
final CommandMessage message;
final Cont cont;
WarpLaneRelayOnCommand(WarpLaneModel model, CommandMessage message, Cont cont) {
super(model, 2);
this.message = message;
this.cont = cont;
}
@Override
protected boolean runPhase(View view, int phase, boolean preemptive) {
if (phase == 0) {
if (preemptive) {
view.laneWillCommand(this.message);
}
return view.dispatchWillCommand(this.message.body(), preemptive);
} else if (phase == 1) {
if (preemptive) {
view.laneDidCommand(this.message);
}
return view.dispatchDidCommand(this.message.body(), preemptive);
} else {
throw new AssertionError(); // unreachable
}
}
@Override
protected void done() {
if (this.cont != null) {
try {
this.cont.bind(this.message);
} catch (Throwable error) {
if (Cont.isNonFatal(error)) {
this.cont.trap(error);
} else {
throw error;
}
}
}
}
}
final class WarpLaneRelayDidUplink extends LaneRelay, View> {
final WarpUplink uplink;
WarpLaneRelayDidUplink(LaneModel model, WarpUplink uplink) {
super(model);
this.uplink = uplink;
}
@Override
protected boolean runPhase(View view, int phase, boolean preemptive) {
if (phase == 0) {
if (preemptive) {
view.laneDidUplink(this.uplink);
}
return view.dispatchDidUplink(this.uplink, preemptive);
} else {
throw new AssertionError(); // unreachable
}
}
}
final class WarpLaneRelayDidEnter extends LaneRelay, View> {
final Identity identity;
WarpLaneRelayDidEnter(WarpLaneModel model, Identity identity) {
super(model);
this.identity = identity;
}
@Override
protected boolean runPhase(View view, int phase, boolean preemptive) {
if (phase == 0) {
if (preemptive) {
view.laneDidEnter(this.identity);
}
return view.dispatchDidEnter(this.identity, preemptive);
} else {
throw new AssertionError(); // unreachable
}
}
}
final class WarpLaneRelayDidLeave extends LaneRelay, View> {
final Identity identity;
WarpLaneRelayDidLeave(WarpLaneModel model, Identity identity) {
super(model);
this.identity = identity;
}
@Override
protected boolean runPhase(View view, int phase, boolean preemptive) {
if (phase == 0) {
if (preemptive) {
view.laneDidLeave(this.identity);
}
return view.dispatchDidLeave(this.identity, preemptive);
} else {
throw new AssertionError(); // unreachable
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy