Move workspace crates into subfolder

This commit is contained in:
Dominik Werder
2023-07-10 14:45:25 +02:00
parent 8938e55f86
commit 30c7fcb1e5
212 changed files with 246 additions and 41 deletions
+197
View File
@@ -0,0 +1,197 @@
use err::Error;
use httpclient::url::Url;
use netpod::log::*;
use netpod::range::evrange::NanoRange;
use netpod::timeunits::DAY;
use netpod::AppendToUrl;
use netpod::ByteOrder;
use netpod::ChConf;
use netpod::ChannelConfigQuery;
use netpod::ChannelConfigResponse;
use netpod::ChannelTypeConfigGen;
use netpod::DtNano;
use netpod::NodeConfigCached;
use netpod::ScalarType;
use netpod::SfChFetchInfo;
use netpod::SfDbChannel;
use netpod::Shape;
use netpod::APP_JSON;
use serde::Serialize;
const TEST_BACKEND: &str = "testbackend-00";
fn channel_config_test_backend(channel: SfDbChannel) -> Result<ChannelTypeConfigGen, Error> {
let backend = channel.backend();
let ret = if channel.name() == "scalar-i32-be" {
let ret = SfChFetchInfo::new(
backend,
channel.name(),
2,
DtNano::from_ns(DAY),
ByteOrder::Big,
ScalarType::I32,
Shape::Scalar,
);
ret
} else if channel.name() == "wave-f64-be-n21" {
let ret = SfChFetchInfo::new(
backend,
channel.name(),
3,
DtNano::from_ns(DAY),
ByteOrder::Big,
ScalarType::F64,
Shape::Wave(21),
);
ret
} else if channel.name() == "const-regular-scalar-i32-be" {
let ret = SfChFetchInfo::new(
backend,
channel.name(),
2,
DtNano::from_ns(DAY),
ByteOrder::Big,
ScalarType::I32,
Shape::Scalar,
);
ret
} else if channel.name() == "test-gen-i32-dim0-v00" {
let ret = SfChFetchInfo::new(
backend,
channel.name(),
2,
DtNano::from_ns(DAY),
ByteOrder::Big,
ScalarType::I32,
Shape::Scalar,
);
ret
} else if channel.name() == "test-gen-i32-dim0-v01" {
let ret = SfChFetchInfo::new(
backend,
channel.name(),
2,
DtNano::from_ns(DAY),
ByteOrder::Big,
ScalarType::I32,
Shape::Scalar,
);
ret
} else if channel.name() == "test-gen-f64-dim1-v00" {
let ret = SfChFetchInfo::new(
backend,
channel.name(),
3,
DtNano::from_ns(DAY),
ByteOrder::Big,
ScalarType::F64,
Shape::Wave(21),
);
ret
} else {
error!("no test information");
return Err(Error::with_msg_no_trace(format!("no test information"))
.add_public_msg("No channel config for test channel {:?}"));
};
Ok(ChannelTypeConfigGen::SfDatabuffer(ret))
}
pub async fn channel_config(
range: NanoRange,
channel: SfDbChannel,
ncc: &NodeConfigCached,
) -> Result<Option<ChannelTypeConfigGen>, Error> {
if channel.backend() == TEST_BACKEND {
Ok(Some(channel_config_test_backend(channel)?))
} else if ncc.node_config.cluster.scylla.is_some() {
debug!("try to get ChConf for scylla type backend");
let ret = dbconn::channelconfig::chconf_from_scylla_type_backend(&channel, ncc)
.await
.map_err(Error::from)?;
Ok(Some(ChannelTypeConfigGen::Scylla(ret)))
} else if ncc.node.sf_databuffer.is_some() {
debug!("channel_config channel {channel:?}");
let k = disk::channelconfig::channel_config_best_match(range, channel.clone(), ncc)
.await
.map_err(|e| Error::from(e.to_string()))?;
match k {
Some(config) => {
debug!("channel_config config {config:?}");
let ret = SfChFetchInfo::new(
config.channel.backend(),
config.channel.name(),
config.keyspace,
config.time_bin_size,
config.byte_order,
config.scalar_type,
config.shape,
);
let ret = ChannelTypeConfigGen::SfDatabuffer(ret);
Ok(Some(ret))
}
None => Ok(None),
}
} else {
return Err(
Error::with_msg_no_trace(format!("no channel config for backend {}", channel.backend()))
.add_public_msg(format!("no channel config for backend {}", channel.backend())),
);
}
}
#[derive(Debug, Serialize)]
pub enum ChannelConfigsGen {
Scylla(ChConf),
SfDatabuffer(disk::parse::channelconfig::ChannelConfigs),
}
pub async fn channel_configs(channel: SfDbChannel, ncc: &NodeConfigCached) -> Result<ChannelConfigsGen, Error> {
if channel.backend() == TEST_BACKEND {
let ret = match channel_config_test_backend(channel)? {
ChannelTypeConfigGen::Scylla(x) => ChannelConfigsGen::Scylla(x),
ChannelTypeConfigGen::SfDatabuffer(x) => ChannelConfigsGen::SfDatabuffer(todo!()),
};
Ok(ret)
} else if ncc.node_config.cluster.scylla.is_some() {
debug!("try to get ChConf for scylla type backend");
let ret = dbconn::channelconfig::chconf_from_scylla_type_backend(&channel, ncc)
.await
.map_err(Error::from)?;
Ok(ChannelConfigsGen::Scylla(ret))
} else if ncc.node.sf_databuffer.is_some() {
debug!("channel_config channel {channel:?}");
let configs = disk::channelconfig::channel_configs(channel.clone(), ncc)
.await
.map_err(|e| Error::from(e.to_string()))?;
Ok(ChannelConfigsGen::SfDatabuffer(configs))
} else {
return Err(
Error::with_msg_no_trace(format!("no channel config for backend {}", channel.backend()))
.add_public_msg(format!("no channel config for backend {}", channel.backend())),
);
}
}
pub async fn http_get_channel_config(
qu: ChannelConfigQuery,
baseurl: Url,
) -> Result<Option<ChannelConfigResponse>, Error> {
let url = baseurl;
let mut url = url.join("channel/config").unwrap();
qu.append_to_url(&mut url);
let res = httpclient::http_get(url, APP_JSON).await?;
use httpclient::http::StatusCode;
if res.head.status == StatusCode::NOT_FOUND {
Ok(None)
} else if res.head.status == StatusCode::OK {
let ret: ChannelConfigResponse = serde_json::from_slice(&res.body)?;
Ok(Some(ret))
} else {
let b = &res.body;
let s = String::from_utf8_lossy(&b[0..b.len().min(256)]);
Err(Error::with_msg_no_trace(format!(
"http_get_channel_config {} {}",
res.head.status, s
)))
}
}
+104
View File
@@ -0,0 +1,104 @@
use crate::channelconfig::http_get_channel_config;
use err::Error;
use netpod::log::*;
use netpod::range::evrange::SeriesRange;
use netpod::ChConf;
use netpod::ChannelConfigQuery;
use netpod::ChannelConfigResponse;
use netpod::ChannelTypeConfigGen;
use netpod::DtNano;
use netpod::NodeConfigCached;
use netpod::SfChFetchInfo;
use netpod::SfDbChannel;
use std::collections::BTreeMap;
use std::time::Duration;
fn decide_sf_ch_config_quorum(inp: Vec<ChannelConfigResponse>) -> Result<Option<ChannelTypeConfigGen>, Error> {
let mut histo = BTreeMap::new();
for item in inp {
let item = match item {
ChannelConfigResponse::SfDatabuffer(k) => ChannelTypeConfigGen::SfDatabuffer(SfChFetchInfo::new(
k.backend,
k.name,
k.keyspace,
DtNano::from_ms(k.timebinsize),
k.byte_order,
k.scalar_type,
k.shape,
)),
ChannelConfigResponse::Daqbuf(k) => {
ChannelTypeConfigGen::Scylla(ChConf::new(k.backend, k.series, k.scalar_type, k.shape, k.name))
}
};
if histo.contains_key(&item) {
*histo.get_mut(&item).unwrap() += 1;
} else {
histo.insert(item, 0u32);
}
}
let mut v: Vec<_> = histo.into_iter().collect();
v.sort_unstable_by_key(|x| x.1);
match v.pop() {
Some((x, _)) => Ok(Some(x)),
None => Ok(None),
}
}
async fn find_sf_ch_config_quorum(
channel: SfDbChannel,
range: SeriesRange,
ncc: &NodeConfigCached,
) -> Result<Option<SfChFetchInfo>, Error> {
let range = match range {
SeriesRange::TimeRange(x) => x,
SeriesRange::PulseRange(_) => return Err(Error::with_msg_no_trace("expect TimeRange")),
};
let mut all = Vec::new();
for node in &ncc.node_config.cluster.nodes {
// TODO add a baseurl function to struct Node
let qu = ChannelConfigQuery {
channel: channel.clone(),
range: range.clone(),
// TODO
expand: false,
};
let res = tokio::time::timeout(Duration::from_millis(4000), http_get_channel_config(qu, node.baseurl()))
.await
.map_err(|_| Error::with_msg_no_trace("timeout"))??;
all.push(res);
}
let all: Vec<_> = all.into_iter().filter_map(|x| x).collect();
let qu = decide_sf_ch_config_quorum(all)?;
match qu {
Some(item) => match item {
ChannelTypeConfigGen::Scylla(_) => Err(Error::with_msg_no_trace(
"find_sf_ch_config_quorum not a sf-databuffer config",
)),
ChannelTypeConfigGen::SfDatabuffer(item) => Ok(Some(item)),
},
None => Ok(None),
}
}
pub async fn find_config_basics_quorum(
channel: SfDbChannel,
range: SeriesRange,
ncc: &NodeConfigCached,
) -> Result<Option<ChannelTypeConfigGen>, Error> {
if let Some(_cfg) = &ncc.node.sf_databuffer {
match find_sf_ch_config_quorum(channel, range, ncc).await? {
Some(x) => Ok(Some(ChannelTypeConfigGen::SfDatabuffer(x))),
None => Ok(None),
}
} else if let Some(_cfg) = &ncc.node_config.cluster.scylla {
// TODO let called function allow to return None instead of error-not-found
let ret = dbconn::channelconfig::chconf_from_scylla_type_backend(&channel, ncc)
.await
.map_err(Error::from)?;
Ok(Some(ChannelTypeConfigGen::Scylla(ret)))
} else {
Err(Error::with_msg_no_trace(
"find_config_basics_quorum not supported backend",
))
}
}
+355
View File
@@ -0,0 +1,355 @@
use crate::scylla::scylla_channel_event_stream;
use err::Error;
use futures_util::Stream;
use futures_util::StreamExt;
use items_0::on_sitemty_data;
use items_0::streamitem::sitem_data;
use items_0::streamitem::LogItem;
use items_0::streamitem::RangeCompletableItem;
use items_0::streamitem::Sitemty;
use items_0::streamitem::StreamItem;
use items_0::streamitem::EVENT_QUERY_JSON_STRING_FRAME;
use items_0::Events;
use items_2::channelevents::ChannelEvents;
use items_2::empty::empty_events_dyn_ev;
use items_2::framable::EventQueryJsonStringFrame;
use items_2::framable::Framable;
use items_2::frame::decode_frame;
use items_2::frame::make_term_frame;
use items_2::inmem::InMemoryFrame;
use netpod::histo::HistoLog2;
use netpod::log::*;
use netpod::NodeConfigCached;
use query::api4::events::EventsSubQuery;
use query::api4::events::Frame1Parts;
use std::net::SocketAddr;
use std::pin::Pin;
use streams::frames::inmem::InMemoryFrameAsyncReadStream;
use streams::generators::GenerateF64V00;
use streams::generators::GenerateI32V00;
use streams::generators::GenerateI32V01;
use streams::transform::build_event_transform;
use tokio::io::AsyncWriteExt;
use tokio::net::tcp::OwnedReadHalf;
use tokio::net::tcp::OwnedWriteHalf;
use tokio::net::TcpStream;
use tracing::Instrument;
const TEST_BACKEND: &str = "testbackend-00";
#[cfg(test)]
mod test;
pub async fn events_service(node_config: NodeConfigCached) -> Result<(), Error> {
let addr = format!("{}:{}", node_config.node.listen, node_config.node.port_raw);
let lis = tokio::net::TcpListener::bind(addr).await?;
loop {
match lis.accept().await {
Ok((stream, addr)) => {
taskrun::spawn(events_conn_handler(stream, addr, node_config.clone()));
}
Err(e) => Err(e)?,
}
}
}
struct ConnErr {
err: Error,
#[allow(dead_code)]
netout: OwnedWriteHalf,
}
impl<E: Into<Error>> From<(E, OwnedWriteHalf)> for ConnErr {
fn from((err, netout): (E, OwnedWriteHalf)) -> Self {
Self {
err: err.into(),
netout,
}
}
}
async fn make_channel_events_stream_data(
subq: EventsSubQuery,
ncc: &NodeConfigCached,
) -> Result<Pin<Box<dyn Stream<Item = Sitemty<ChannelEvents>> + Send>>, Error> {
if subq.backend() == TEST_BACKEND {
debug!("use test backend data {}", TEST_BACKEND);
let node_count = ncc.node_config.cluster.nodes.len() as u64;
let node_ix = ncc.ix as u64;
let chn = subq.name();
let range = subq.range().clone();
let one_before = subq.transform().need_one_before_range();
if chn == "test-gen-i32-dim0-v00" {
Ok(Box::pin(GenerateI32V00::new(node_ix, node_count, range, one_before)))
} else if chn == "test-gen-i32-dim0-v01" {
Ok(Box::pin(GenerateI32V01::new(node_ix, node_count, range, one_before)))
} else if chn == "test-gen-f64-dim1-v00" {
Ok(Box::pin(GenerateF64V00::new(node_ix, node_count, range, one_before)))
} else {
let na: Vec<_> = chn.split("-").collect();
if na.len() != 3 {
Err(Error::with_msg_no_trace(format!(
"make_channel_events_stream_data can not understand test channel name: {chn:?}"
)))
} else {
if na[0] != "inmem" {
Err(Error::with_msg_no_trace(format!(
"make_channel_events_stream_data can not understand test channel name: {chn:?}"
)))
} else {
let _range = subq.range().clone();
if na[1] == "d0" {
if na[2] == "i32" {
//generator::generate_i32(node_ix, node_count, range)
panic!()
} else if na[2] == "f32" {
//generator::generate_f32(node_ix, node_count, range)
panic!()
} else {
Err(Error::with_msg_no_trace(format!(
"make_channel_events_stream_data can not understand test channel name: {chn:?}"
)))
}
} else {
Err(Error::with_msg_no_trace(format!(
"make_channel_events_stream_data can not understand test channel name: {chn:?}"
)))
}
}
}
}
} else if let Some(scyconf) = &ncc.node_config.cluster.scylla {
let cfg = subq.ch_conf().to_scylla()?;
scylla_channel_event_stream(subq, cfg, scyconf, ncc).await
} else if let Some(_) = &ncc.node.channel_archiver {
let e = Error::with_msg_no_trace("archapp not built");
Err(e)
} else if let Some(_) = &ncc.node.archiver_appliance {
let e = Error::with_msg_no_trace("archapp not built");
Err(e)
} else {
let cfg = subq.ch_conf().to_sf_databuffer()?;
Ok(disk::raw::conn::make_event_pipe(subq, cfg, ncc).await?)
}
}
async fn make_channel_events_stream(
subq: EventsSubQuery,
ncc: &NodeConfigCached,
) -> Result<Pin<Box<dyn Stream<Item = Sitemty<ChannelEvents>> + Send>>, Error> {
let empty = empty_events_dyn_ev(subq.ch_conf().scalar_type(), subq.ch_conf().shape())?;
let empty = sitem_data(ChannelEvents::Events(empty));
let stream = make_channel_events_stream_data(subq, ncc).await?;
let ret = futures_util::stream::iter([empty]).chain(stream);
let ret = Box::pin(ret);
Ok(ret)
}
async fn events_get_input_frames(netin: OwnedReadHalf) -> Result<Vec<InMemoryFrame>, Error> {
let mut h = InMemoryFrameAsyncReadStream::new(netin, netpod::ByteSize::from_kb(1));
let mut frames = Vec::new();
while let Some(k) = h
.next()
.instrument(span!(Level::INFO, "events_conn_handler/query-input"))
.await
{
match k {
Ok(StreamItem::DataItem(item)) => {
frames.push(item);
}
Ok(item) => {
debug!("ignored incoming frame {:?}", item);
}
Err(e) => {
return Err(e);
}
}
}
Ok(frames)
}
async fn events_parse_input_query(frames: Vec<InMemoryFrame>) -> Result<(EventsSubQuery,), Error> {
if frames.len() != 1 {
error!("{:?}", frames);
error!("missing command frame len {}", frames.len());
let e = Error::with_msg("missing command frame");
return Err(e);
}
let query_frame = &frames[0];
if query_frame.tyid() != EVENT_QUERY_JSON_STRING_FRAME {
return Err(Error::with_msg("query frame wrong type"));
}
// TODO this does not need all variants of Sitemty.
let qitem = match decode_frame::<Sitemty<EventQueryJsonStringFrame>>(query_frame) {
Ok(k) => match k {
Ok(k) => match k {
StreamItem::DataItem(k) => match k {
RangeCompletableItem::Data(k) => k,
RangeCompletableItem::RangeComplete => return Err(Error::with_msg("bad query item")),
},
_ => return Err(Error::with_msg("bad query item")),
},
Err(e) => return Err(e),
},
Err(e) => return Err(e),
};
let frame1: Frame1Parts = serde_json::from_str(&qitem.str()).map_err(|e| {
let e = Error::with_msg_no_trace(format!("json parse error: {} inp {:?}", e, qitem.str()));
error!("{e}");
e
})?;
Ok(frame1.parts())
}
async fn events_conn_handler_inner_try(
stream: TcpStream,
addr: SocketAddr,
ncc: &NodeConfigCached,
) -> Result<(), ConnErr> {
let _ = addr;
let (netin, mut netout) = stream.into_split();
let frames = match events_get_input_frames(netin).await {
Ok(x) => x,
Err(e) => return Err((e, netout).into()),
};
let (evq,) = match events_parse_input_query(frames).await {
Ok(x) => x,
Err(e) => return Err((e, netout).into()),
};
info!("events_parse_input_query {evq:?}");
if evq.create_errors_contains("nodenet_parse_query") {
let e = Error::with_msg_no_trace("produced error on request nodenet_parse_query");
return Err((e, netout).into());
}
let mut stream: Pin<Box<dyn Stream<Item = Box<dyn Framable + Send>> + Send>> = if evq.is_event_blobs() {
// TODO support event blobs as transform
let fetch_info = match evq.ch_conf().to_sf_databuffer() {
Ok(x) => x,
Err(e) => return Err((e, netout).into()),
};
match disk::raw::conn::make_event_blobs_pipe(&evq, &fetch_info, ncc).await {
Ok(stream) => {
let stream = stream.map(|x| Box::new(x) as _);
Box::pin(stream)
}
Err(e) => return Err((e, netout).into()),
}
} else {
match make_channel_events_stream(evq.clone(), ncc).await {
Ok(stream) => {
if false {
// TODO wasm example
use wasmer::Value;
let wasm = b"";
let mut store = wasmer::Store::default();
let module = wasmer::Module::new(&store, wasm).unwrap();
let import_object = wasmer::imports! {};
let instance = wasmer::Instance::new(&mut store, &module, &import_object).unwrap();
let add_one = instance.exports.get_function("event_transform").unwrap();
let result = add_one.call(&mut store, &[Value::I32(42)]).unwrap();
assert_eq!(result[0], Value::I32(43));
}
let mut tr = match build_event_transform(evq.transform()) {
Ok(x) => x,
Err(e) => {
return Err((e, netout).into());
}
};
let stream = stream.map(move |x| {
let item = on_sitemty_data!(x, |x| {
let x: Box<dyn Events> = Box::new(x);
let x = tr.0.transform(x);
Ok(StreamItem::DataItem(RangeCompletableItem::Data(x)))
});
Box::new(item) as Box<dyn Framable + Send>
});
Box::pin(stream)
}
Err(e) => {
return Err((e, netout).into());
}
}
};
let mut buf_len_histo = HistoLog2::new(5);
while let Some(item) = stream.next().await {
let item = item.make_frame();
match item {
Ok(buf) => {
buf_len_histo.ingest(buf.len() as u32);
match netout.write_all(&buf).await {
Ok(()) => {
// TODO collect timing information and send as summary in a stats item.
// TODO especially collect a distribution over the buf lengths that were send.
// TODO we want to see a reasonable batch size.
}
Err(e) => return Err((e, netout))?,
}
}
Err(e) => {
error!("events_conn_handler_inner_try sees error in stream: {e:?}");
return Err((e, netout))?;
}
}
}
{
let item = LogItem {
node_ix: ncc.ix as _,
level: Level::INFO,
msg: format!("buf_len_histo: {:?}", buf_len_histo),
};
let item: Sitemty<ChannelEvents> = Ok(StreamItem::Log(item));
let buf = match item.make_frame() {
Ok(k) => k,
Err(e) => return Err((e, netout))?,
};
match netout.write_all(&buf).await {
Ok(()) => (),
Err(e) => return Err((e, netout))?,
}
}
let buf = match make_term_frame() {
Ok(k) => k,
Err(e) => return Err((e, netout))?,
};
match netout.write_all(&buf).await {
Ok(()) => (),
Err(e) => return Err((e, netout))?,
}
match netout.flush().await {
Ok(()) => (),
Err(e) => return Err((e, netout))?,
}
Ok(())
}
async fn events_conn_handler_inner(
stream: TcpStream,
addr: SocketAddr,
node_config: &NodeConfigCached,
) -> Result<(), Error> {
match events_conn_handler_inner_try(stream, addr, node_config).await {
Ok(_) => (),
Err(ce) => {
let mut out = ce.netout;
let item: Sitemty<ChannelEvents> = Err(ce.err);
let buf = Framable::make_frame(&item)?;
out.write_all(&buf).await?;
}
}
Ok(())
}
async fn events_conn_handler(stream: TcpStream, addr: SocketAddr, node_config: NodeConfigCached) -> Result<(), Error> {
let span1 = span!(Level::INFO, "events_conn_handler");
let r = events_conn_handler_inner(stream, addr, &node_config)
.instrument(span1)
.await;
match r {
Ok(k) => Ok(k),
Err(e) => {
error!("events_conn_handler sees error: {:?}", e);
Err(e)
}
}
}
+138
View File
@@ -0,0 +1,138 @@
use crate::conn::events_conn_handler;
use crate::conn::Frame1Parts;
use err::Error;
use futures_util::StreamExt;
use items_0::streamitem::sitem_data;
use items_0::streamitem::Sitemty;
use items_0::streamitem::StreamItem;
use items_0::streamitem::ERROR_FRAME_TYPE_ID;
use items_0::streamitem::ITEMS_2_CHANNEL_EVENTS_FRAME_TYPE_ID;
use items_0::streamitem::LOG_FRAME_TYPE_ID;
use items_0::streamitem::STATS_FRAME_TYPE_ID;
use items_2::channelevents::ChannelEvents;
use items_2::framable::EventQueryJsonStringFrame;
use items_2::framable::Framable;
use items_2::frame::decode_frame;
use netpod::range::evrange::NanoRange;
use netpod::timeunits::DAY;
use netpod::timeunits::SEC;
use netpod::ByteOrder;
use netpod::Cluster;
use netpod::Database;
use netpod::DtNano;
use netpod::FileIoBufferSize;
use netpod::Node;
use netpod::NodeConfig;
use netpod::NodeConfigCached;
use netpod::ScalarType;
use netpod::SfChFetchInfo;
use netpod::SfDatabuffer;
use netpod::Shape;
use query::api4::events::EventsSubQuery;
use query::api4::events::EventsSubQuerySelect;
use query::api4::events::EventsSubQuerySettings;
use query::transform::TransformQuery;
use streams::frames::inmem::InMemoryFrameAsyncReadStream;
use tokio::io::AsyncWriteExt;
use tokio::net::TcpListener;
use tokio::net::TcpStream;
const TEST_BACKEND: &str = "testbackend-00";
#[test]
fn raw_data_00() {
let fut = async {
let lis = TcpListener::bind("127.0.0.1:0").await.unwrap();
let mut con = TcpStream::connect(lis.local_addr().unwrap()).await.unwrap();
let (client, addr) = lis.accept().await.unwrap();
let cfg = NodeConfigCached {
node_config: NodeConfig {
name: "node_name_dummy".into(),
cluster: Cluster {
backend: TEST_BACKEND.into(),
nodes: Vec::new(),
database: Database {
name: "".into(),
host: "".into(),
port: 5432,
user: "".into(),
pass: "".into(),
},
run_map_pulse_task: false,
is_central_storage: false,
file_io_buffer_size: FileIoBufferSize(1024 * 8),
scylla: None,
cache_scylla: None,
},
},
node: Node {
host: "empty".into(),
listen: "listen_dummy".into(),
port: 9090,
port_raw: 9090,
cache_base_path: "".into(),
sf_databuffer: Some(SfDatabuffer {
data_base_path: "/home/dominik/daqbuffer-testdata/databuffer/node00".into(),
ksprefix: "ks".into(),
splits: None,
}),
archiver_appliance: None,
channel_archiver: None,
prometheus_api_bind: None,
},
ix: 0,
};
let range = NanoRange {
beg: SEC,
end: SEC * 10,
};
let fetch_info = SfChFetchInfo::new(
TEST_BACKEND,
"scalar-i32",
2,
DtNano::from_ns(DAY),
ByteOrder::Big,
ScalarType::I32,
Shape::Scalar,
);
let select = EventsSubQuerySelect::new(fetch_info.into(), range.into(), TransformQuery::default_events());
let settings = EventsSubQuerySettings::default();
let qu = EventsSubQuery::from_parts(select, settings);
let frame1 = Frame1Parts::new(qu.clone());
let query = EventQueryJsonStringFrame(serde_json::to_string(&frame1).unwrap());
let frame = sitem_data(query).make_frame()?;
let jh = taskrun::spawn(events_conn_handler(client, addr, cfg));
con.write_all(&frame).await.unwrap();
eprintln!("written");
con.shutdown().await.unwrap();
eprintln!("shut down");
let mut frames = InMemoryFrameAsyncReadStream::new(con, qu.inmem_bufcap());
while let Some(frame) = frames.next().await {
match frame {
Ok(frame) => match frame {
StreamItem::DataItem(k) => {
eprintln!("{k:?}");
if k.tyid() == ITEMS_2_CHANNEL_EVENTS_FRAME_TYPE_ID {
} else if k.tyid() == ERROR_FRAME_TYPE_ID {
} else if k.tyid() == LOG_FRAME_TYPE_ID {
} else if k.tyid() == STATS_FRAME_TYPE_ID {
} else {
panic!("unexpected frame type id {:x}", k.tyid());
}
let item: Sitemty<ChannelEvents> = decode_frame(&k).unwrap();
eprintln!("decoded: {:?}", item);
}
StreamItem::Log(_) => todo!(),
StreamItem::Stats(_) => todo!(),
},
Err(e) => {
panic!("{e:?}");
}
}
}
jh.await.unwrap().unwrap();
Ok::<_, Error>(())
};
taskrun::run(fut).unwrap();
}
+4
View File
@@ -0,0 +1,4 @@
pub mod channelconfig;
pub mod configquorum;
pub mod conn;
pub mod scylla;
+80
View File
@@ -0,0 +1,80 @@
use err::Error;
use futures_util::Stream;
use futures_util::StreamExt;
use items_0::streamitem::RangeCompletableItem;
use items_0::streamitem::Sitemty;
use items_0::streamitem::StreamItem;
use items_2::channelevents::ChannelEvents;
use netpod::log::*;
use netpod::ChConf;
use netpod::NodeConfigCached;
use netpod::ScyllaConfig;
use query::api4::events::EventsSubQuery;
use std::pin::Pin;
pub async fn scylla_channel_event_stream(
evq: EventsSubQuery,
chconf: ChConf,
scyco: &ScyllaConfig,
_ncc: &NodeConfigCached,
) -> Result<Pin<Box<dyn Stream<Item = Sitemty<ChannelEvents>> + Send>>, Error> {
// TODO depends in general on the query
// TODO why both in PlainEventsQuery and as separate parameter? Check other usages.
let do_one_before_range = false;
// TODO use better builder pattern with shortcuts for production and dev defaults
let scy = scyllaconn::create_scy_session(scyco).await?;
let series = chconf.series();
let scalar_type = chconf.scalar_type();
let shape = chconf.shape();
let do_test_stream_error = false;
let with_values = evq.need_value_data();
debug!("Make EventsStreamScylla for {series:?} {scalar_type:?} {shape:?}");
let stream = scyllaconn::events::EventsStreamScylla::new(
series,
evq.range().into(),
do_one_before_range,
scalar_type.clone(),
shape.clone(),
with_values,
scy,
do_test_stream_error,
);
let stream = stream
.map(move |item| match &item {
Ok(k) => match k {
ChannelEvents::Events(k) => {
let n = k.len();
let d = evq.event_delay();
(item, n, d.clone())
}
ChannelEvents::Status(_) => (item, 1, None),
},
Err(_) => (item, 1, None),
})
.then(|(item, n, d)| async move {
if let Some(d) = d {
warn!("sleep {} times {:?}", n, d);
tokio::time::sleep(d.saturating_mul(n as _)).await;
}
item
})
.map(|item| {
let item = match item {
Ok(item) => match item {
ChannelEvents::Events(item) => {
let item = ChannelEvents::Events(item);
let item = Ok(StreamItem::DataItem(RangeCompletableItem::Data(item)));
item
}
ChannelEvents::Status(item) => {
let item = ChannelEvents::Status(item);
let item = Ok(StreamItem::DataItem(RangeCompletableItem::Data(item)));
item
}
},
Err(e) => Err(e),
};
item
});
Ok(Box::pin(stream))
}