ci/woodpecker/push/main-amd64-build Pipeline was successful
Namespaces, assemblies, solution, binaries, images, systemd units, config paths, environment variables, protocol methods and the Linux user are all renamed. Breaking: existing databases, node identities and installed units must be recreated.
129 lines
4.7 KiB
C#
129 lines
4.7 KiB
C#
namespace MoShiro.Protocol;
|
||
|
||
[Flags]
|
||
public enum Scope
|
||
{
|
||
Line = 1,
|
||
Target = 2,
|
||
}
|
||
|
||
public enum ColumnType
|
||
{
|
||
U8,
|
||
U16,
|
||
U32,
|
||
U64,
|
||
I32,
|
||
I64,
|
||
}
|
||
|
||
public enum ColumnEnc
|
||
{
|
||
Plain,
|
||
Delta,
|
||
}
|
||
|
||
/// <summary>时间列的时钟归属:Probe、Agent 各自的单调时钟(微秒),或所在一侧的本地时钟。</summary>
|
||
public enum ColumnRole
|
||
{
|
||
None,
|
||
TsProbe,
|
||
TsAgent,
|
||
TsLocal,
|
||
}
|
||
|
||
public sealed record ColumnSpec(string Name, ColumnType Type, ColumnEnc Enc = ColumnEnc.Plain, bool Nullable = false, ColumnRole Role = ColumnRole.None);
|
||
|
||
/// <summary>数据面上的一侧:Probe 永远是拨号方,Agent 永远是监听方。</summary>
|
||
public enum Side
|
||
{
|
||
Probe,
|
||
Agent,
|
||
}
|
||
|
||
/// <summary>
|
||
/// 一个记录流(一张表)。<see cref="Driver"/> 是行的主导方:行由它发出的包或事件决定,另一侧的列按 <see cref="Key"/>(例如 <c>seq</c>)补充,
|
||
/// 缺失就是缺失(回显缺 t2/t3 表示上行丢失,单向数据流缺 t_recv 表示丢失)。没有 <see cref="Key"/> 的流只有主导方一侧的列,原样透传。
|
||
/// 每一列属于哪一侧由它的时钟决定(<c>TsProbe</c> 属于 Probe,<c>TsAgent</c> 属于 Agent),其他列属于主导方。
|
||
/// <see cref="Union"/> 流是例外:两侧各自记录完整的行(行里有一列标明是哪一侧),合并时直接拼接,不连接。
|
||
/// 这一条声明同时决定了两端各记录什么、Agent 怎么合并,新增一种记录流不需要写合并代码。
|
||
/// </summary>
|
||
public sealed record StreamSpec(string Name, IReadOnlyList<ColumnSpec> Columns, Side Driver = Side.Probe, string? Key = null, bool Union = false)
|
||
{
|
||
public Side OwnerOf(ColumnSpec column) => column.Role switch
|
||
{
|
||
ColumnRole.TsProbe => Side.Probe,
|
||
ColumnRole.TsAgent => Side.Agent,
|
||
_ => Driver,
|
||
};
|
||
|
||
/// <summary>
|
||
/// 该侧记录的列(不含连接键:键两侧都有,由行的编号表示)。<see cref="Union"/> 流两侧各自记录完整的行(例如各自套接字的内核采样),
|
||
/// 所以每一侧拥有所有列。
|
||
/// </summary>
|
||
public IReadOnlyList<ColumnSpec> ColumnsOf(Side side) =>
|
||
[.. Columns.Where(c => c.Name != Key && (Union || OwnerOf(c) == side))];
|
||
}
|
||
|
||
/// <summary>积木组合(只描述,不含代码;节点按这个描述组装执行图)。</summary>
|
||
public sealed record BlockSet(string Transport, string Pacer, string Payload, string Behavior, IReadOnlyList<string> Samplers);
|
||
|
||
/// <summary>
|
||
/// 采集方法声明:积木组合 + 参数 + 记录的列 + 带宽预算。
|
||
/// 这一条声明同时被 Probe/Agent(组装执行)、Backend(校验与目录)、Analysis(按列名读数据)使用。
|
||
/// </summary>
|
||
public sealed record KindSpec(
|
||
string Id,
|
||
string Title,
|
||
string Description,
|
||
Scope Scopes,
|
||
BlockSet Blocks,
|
||
IReadOnlyList<ParamSpec> Params,
|
||
IReadOnlyList<StreamSpec> Streams,
|
||
Func<ParamValues, long> BudgetBitsPerSecond)
|
||
{
|
||
public StreamSpec? FindStream(string name)
|
||
{
|
||
foreach (StreamSpec stream in Streams)
|
||
{
|
||
if (stream.Name == name)
|
||
{
|
||
return stream;
|
||
}
|
||
}
|
||
|
||
return null;
|
||
}
|
||
}
|
||
|
||
public static class Col
|
||
{
|
||
public static ColumnSpec U8(string name, bool nullable = false) => new(name, ColumnType.U8, ColumnEnc.Plain, nullable);
|
||
|
||
public static ColumnSpec U16(string name, bool nullable = false) => new(name, ColumnType.U16, ColumnEnc.Plain, nullable);
|
||
|
||
public static ColumnSpec U32(string name, bool nullable = false) => new(name, ColumnType.U32, ColumnEnc.Plain, nullable);
|
||
|
||
public static ColumnSpec U64(string name, ColumnEnc enc = ColumnEnc.Plain) => new(name, ColumnType.U64, enc);
|
||
|
||
/// <summary>单调递增的序号:差分编码。</summary>
|
||
public static ColumnSpec Seq(string name) => new(name, ColumnType.U32, ColumnEnc.Delta);
|
||
|
||
public static ColumnSpec TsProbe(string name, bool nullable = false) => new(name, ColumnType.I64, ColumnEnc.Delta, nullable, ColumnRole.TsProbe);
|
||
|
||
public static ColumnSpec TsAgent(string name, bool nullable = false) => new(name, ColumnType.I64, ColumnEnc.Delta, nullable, ColumnRole.TsAgent);
|
||
|
||
public static ColumnSpec TsLocal(string name) => new(name, ColumnType.I64, ColumnEnc.Delta, false, ColumnRole.TsLocal);
|
||
}
|
||
|
||
/// <summary>带宽预算的估算函数(bit/s)。</summary>
|
||
public static class Bandwidth
|
||
{
|
||
private const int UdpOverheadBytes = 28;
|
||
private const int TcpOverheadBytes = 52;
|
||
|
||
public static long UdpEcho(long rateHz, long sizeBytes) => rateHz * ((sizeBytes + UdpOverheadBytes) * 8) * 2;
|
||
|
||
public static long TcpEcho(long rateHz, long sizeBytes) => rateHz * ((sizeBytes + TcpOverheadBytes) * 8) * 2;
|
||
}
|