WIP
This commit is contained in:
@@ -1,278 +1,8 @@
|
||||
use err::Error;
|
||||
use futures_util::Stream;
|
||||
use futures_util::StreamExt;
|
||||
use items_0::streamitem::sitem_data;
|
||||
use items_0::streamitem::RangeCompletableItem;
|
||||
use items_0::streamitem::Sitemty;
|
||||
use items_0::streamitem::StreamItem;
|
||||
use items_0::timebin::TimeBinnableTy;
|
||||
use items_0::timebin::TimeBinnerTy;
|
||||
use netpod::log::*;
|
||||
use netpod::BinnedRangeEnum;
|
||||
use std::any;
|
||||
use std::fmt;
|
||||
use std::ops::ControlFlow;
|
||||
use std::pin::Pin;
|
||||
use std::task::Context;
|
||||
use std::task::Poll;
|
||||
mod basic;
|
||||
mod cached;
|
||||
mod fromlayers;
|
||||
mod gapfill;
|
||||
mod grid;
|
||||
|
||||
#[allow(unused)]
|
||||
macro_rules! trace2 {
|
||||
($($arg:tt)*) => {};
|
||||
($($arg:tt)*) => { trace!($($arg)*) };
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
macro_rules! trace3 {
|
||||
($($arg:tt)*) => {};
|
||||
($($arg:tt)*) => { trace!($($arg)*) };
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
macro_rules! trace4 {
|
||||
($($arg:tt)*) => {};
|
||||
($($arg:tt)*) => { trace!($($arg)*) };
|
||||
}
|
||||
|
||||
type MergeInp<T> = Pin<Box<dyn Stream<Item = Sitemty<T>> + Send>>;
|
||||
|
||||
pub struct TimeBinnedStream<T>
|
||||
where
|
||||
T: TimeBinnableTy,
|
||||
{
|
||||
inp: MergeInp<T>,
|
||||
range: BinnedRangeEnum,
|
||||
do_time_weight: bool,
|
||||
range_final: bool,
|
||||
binner: Option<<T as TimeBinnableTy>::TimeBinner>,
|
||||
done_first_input: bool,
|
||||
done_data: bool,
|
||||
done: bool,
|
||||
complete: bool,
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for TimeBinnedStream<T>
|
||||
where
|
||||
T: TimeBinnableTy,
|
||||
{
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.debug_struct(any::type_name::<Self>())
|
||||
.field("range", &self.range)
|
||||
.field("range_final", &self.range_final)
|
||||
.field("binner", &self.binner)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TimeBinnedStream<T>
|
||||
where
|
||||
T: TimeBinnableTy,
|
||||
{
|
||||
pub fn new(inp: MergeInp<T>, range: BinnedRangeEnum, do_time_weight: bool) -> Self {
|
||||
Self {
|
||||
inp,
|
||||
range,
|
||||
do_time_weight,
|
||||
range_final: false,
|
||||
binner: None,
|
||||
done_first_input: false,
|
||||
done_data: false,
|
||||
done: false,
|
||||
complete: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn process_item(&mut self, mut item: T) -> () {
|
||||
let emit_empty_bins = true;
|
||||
trace2!("process_item {item:?}");
|
||||
if self.binner.is_none() {
|
||||
trace!("process_item call time_binner_new");
|
||||
let binner = item.time_binner_new(self.range.clone(), self.do_time_weight, emit_empty_bins);
|
||||
self.binner = Some(binner);
|
||||
}
|
||||
let binner = self.binner.as_mut().unwrap();
|
||||
trace2!("process_item call binner ingest");
|
||||
binner.ingest(&mut item);
|
||||
}
|
||||
|
||||
fn handle_data_item(
|
||||
&mut self,
|
||||
item: T,
|
||||
) -> Result<ControlFlow<Poll<Sitemty<<<T as TimeBinnableTy>::TimeBinner as TimeBinnerTy>::Output>>>, Error> {
|
||||
use ControlFlow::*;
|
||||
use Poll::*;
|
||||
trace2!("================= handle_data_item");
|
||||
let item_len = item.len();
|
||||
self.process_item(item);
|
||||
let mut do_emit = false;
|
||||
if self.done_first_input == false {
|
||||
debug!(
|
||||
"emit container after the first input len {} binner {}",
|
||||
item_len,
|
||||
self.binner.is_some()
|
||||
);
|
||||
if self.binner.is_none() {
|
||||
let e = Error::with_msg_no_trace("must emit on first input but no binner");
|
||||
self.done = true;
|
||||
return Err(e);
|
||||
}
|
||||
do_emit = true;
|
||||
self.done_first_input = true;
|
||||
}
|
||||
if let Some(binner) = self.binner.as_mut() {
|
||||
trace3!("bins ready count {}", binner.bins_ready_count());
|
||||
if binner.bins_ready_count() > 0 {
|
||||
do_emit = true
|
||||
}
|
||||
if do_emit {
|
||||
if let Some(bins) = binner.bins_ready() {
|
||||
Ok(Break(Ready(sitem_data(bins))))
|
||||
} else {
|
||||
if let Some(bins) = binner.empty() {
|
||||
Ok(Break(Ready(sitem_data(bins))))
|
||||
} else {
|
||||
let e = Error::with_msg_no_trace("must emit but can not even create empty A");
|
||||
error!("{e}");
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
trace3!("not emit");
|
||||
Ok(ControlFlow::Continue(()))
|
||||
}
|
||||
} else {
|
||||
warn!("processed item, but no binner yet");
|
||||
Ok(ControlFlow::Continue(()))
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_item(
|
||||
&mut self,
|
||||
item: Result<StreamItem<RangeCompletableItem<T>>, Error>,
|
||||
) -> Result<ControlFlow<Poll<Sitemty<<<T as TimeBinnableTy>::TimeBinner as TimeBinnerTy>::Output>>>, Error> {
|
||||
use ControlFlow::*;
|
||||
use Poll::*;
|
||||
trace2!("================= handle_item");
|
||||
match item {
|
||||
Ok(item) => match item {
|
||||
StreamItem::DataItem(item) => match item {
|
||||
RangeCompletableItem::RangeComplete => {
|
||||
debug!("see RangeComplete");
|
||||
self.range_final = true;
|
||||
Ok(Continue(()))
|
||||
}
|
||||
RangeCompletableItem::Data(item) => self.handle_data_item(item),
|
||||
},
|
||||
StreamItem::Log(item) => Ok(Break(Ready(Ok(StreamItem::Log(item))))),
|
||||
StreamItem::Stats(item) => Ok(Break(Ready(Ok(StreamItem::Stats(item))))),
|
||||
},
|
||||
Err(e) => {
|
||||
error!("received error item: {e}");
|
||||
self.done = true;
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_none(
|
||||
&mut self,
|
||||
) -> Result<ControlFlow<Poll<Sitemty<<<T as TimeBinnableTy>::TimeBinner as TimeBinnerTy>::Output>>>, Error> {
|
||||
use ControlFlow::*;
|
||||
use Poll::*;
|
||||
trace2!("================= handle_none");
|
||||
let self_range_final = self.range_final;
|
||||
if let Some(binner) = self.binner.as_mut() {
|
||||
trace!("bins ready count before finish {}", binner.bins_ready_count());
|
||||
// TODO rework the finish logic
|
||||
if self_range_final {
|
||||
binner.set_range_complete();
|
||||
}
|
||||
binner.push_in_progress(false);
|
||||
trace!("bins ready count after finish {}", binner.bins_ready_count());
|
||||
if let Some(bins) = binner.bins_ready() {
|
||||
self.done_data = true;
|
||||
Ok(Break(Ready(sitem_data(bins))))
|
||||
} else {
|
||||
if let Some(bins) = binner.empty() {
|
||||
self.done_data = true;
|
||||
Ok(Break(Ready(sitem_data(bins))))
|
||||
} else {
|
||||
let e = Error::with_msg_no_trace("must emit but can not even create empty B");
|
||||
error!("{e}");
|
||||
self.done_data = true;
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warn!("input stream finished, still no binner");
|
||||
self.done_data = true;
|
||||
let e = Error::with_msg_no_trace(format!("input stream finished, still no binner"));
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
// Original block inside the poll loop was able to:
|
||||
// continue
|
||||
// break with Poll<Option<Item>>
|
||||
fn poll_input(
|
||||
&mut self,
|
||||
cx: &mut Context,
|
||||
) -> Result<ControlFlow<Poll<Sitemty<<<T as TimeBinnableTy>::TimeBinner as TimeBinnerTy>::Output>>>, Error> {
|
||||
use ControlFlow::*;
|
||||
use Poll::*;
|
||||
trace2!("================= poll_input");
|
||||
match self.inp.poll_next_unpin(cx) {
|
||||
Ready(Some(item)) => self.handle_item(item),
|
||||
Ready(None) => self.handle_none(),
|
||||
Pending => Ok(Break(Pending)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Stream for TimeBinnedStream<T>
|
||||
where
|
||||
T: TimeBinnableTy + Unpin,
|
||||
{
|
||||
type Item = Sitemty<<<T as TimeBinnableTy>::TimeBinner as TimeBinnerTy>::Output>;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
|
||||
use Poll::*;
|
||||
let span = span!(Level::INFO, "TimeBinner");
|
||||
let _spg = span.enter();
|
||||
trace2!("================= POLL");
|
||||
loop {
|
||||
break if self.complete {
|
||||
panic!("TimeBinnedStream poll on complete")
|
||||
} else if self.done {
|
||||
self.complete = true;
|
||||
Ready(None)
|
||||
} else if self.done_data {
|
||||
self.done = true;
|
||||
if self.range_final {
|
||||
Ready(Some(Ok(StreamItem::DataItem(RangeCompletableItem::RangeComplete))))
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
match self.poll_input(cx) {
|
||||
Ok(item) => match item {
|
||||
ControlFlow::Continue(()) => continue,
|
||||
ControlFlow::Break(item) => match item {
|
||||
Ready(item) => break Ready(Some(item)),
|
||||
Pending => break Pending,
|
||||
},
|
||||
},
|
||||
Err(e) => {
|
||||
self.done = true;
|
||||
break Ready(Some(Err(e)));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//impl<T> WithTransformProperties for TimeBinnedStream<T> where T: TimeBinnableTy {}
|
||||
|
||||
//impl<T> TimeBinnableStreamTrait for TimeBinnedStream<T> where T: TimeBinnableTy {}
|
||||
pub(super) use basic::TimeBinnedStream;
|
||||
pub(super) use fromlayers::TimeBinnedFromLayers;
|
||||
|
||||
287
crates/streams/src/timebin/basic.rs
Normal file
287
crates/streams/src/timebin/basic.rs
Normal file
@@ -0,0 +1,287 @@
|
||||
use err::Error;
|
||||
use futures_util::Stream;
|
||||
use futures_util::StreamExt;
|
||||
use items_0::streamitem::sitem_data;
|
||||
use items_0::streamitem::RangeCompletableItem;
|
||||
use items_0::streamitem::Sitemty;
|
||||
use items_0::streamitem::StreamItem;
|
||||
use items_0::timebin::TimeBinnableTy;
|
||||
use items_0::timebin::TimeBinnerTy;
|
||||
use netpod::log::*;
|
||||
use netpod::BinnedRangeEnum;
|
||||
use std::any;
|
||||
use std::fmt;
|
||||
use std::ops::ControlFlow;
|
||||
use std::pin::Pin;
|
||||
use std::task::Context;
|
||||
use std::task::Poll;
|
||||
|
||||
#[allow(unused)]
|
||||
macro_rules! trace2 {
|
||||
($($arg:tt)*) => {
|
||||
if false {
|
||||
trace!($($arg)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
macro_rules! trace3 {
|
||||
($($arg:tt)*) => {
|
||||
if false {
|
||||
trace!($($arg)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
macro_rules! trace4 {
|
||||
($($arg:tt)*) => {
|
||||
if false {
|
||||
trace!($($arg)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
type SitemtyStream<T> = Pin<Box<dyn Stream<Item = Sitemty<T>> + Send>>;
|
||||
|
||||
pub struct TimeBinnedStream<T>
|
||||
where
|
||||
T: TimeBinnableTy,
|
||||
{
|
||||
inp: SitemtyStream<T>,
|
||||
range: BinnedRangeEnum,
|
||||
do_time_weight: bool,
|
||||
range_final: bool,
|
||||
binner: Option<<T as TimeBinnableTy>::TimeBinner>,
|
||||
done_first_input: bool,
|
||||
done_data: bool,
|
||||
done: bool,
|
||||
complete: bool,
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for TimeBinnedStream<T>
|
||||
where
|
||||
T: TimeBinnableTy,
|
||||
{
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.debug_struct(any::type_name::<Self>())
|
||||
.field("range", &self.range)
|
||||
.field("range_final", &self.range_final)
|
||||
.field("binner", &self.binner)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TimeBinnedStream<T>
|
||||
where
|
||||
T: TimeBinnableTy,
|
||||
{
|
||||
pub fn new(inp: SitemtyStream<T>, range: BinnedRangeEnum, do_time_weight: bool) -> Self {
|
||||
Self {
|
||||
inp,
|
||||
range,
|
||||
do_time_weight,
|
||||
range_final: false,
|
||||
binner: None,
|
||||
done_first_input: false,
|
||||
done_data: false,
|
||||
done: false,
|
||||
complete: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn process_item(&mut self, mut item: T) -> () {
|
||||
let emit_empty_bins = true;
|
||||
trace2!("process_item {item:?}");
|
||||
if self.binner.is_none() {
|
||||
trace!("process_item call time_binner_new");
|
||||
let binner = item.time_binner_new(self.range.clone(), self.do_time_weight, emit_empty_bins);
|
||||
self.binner = Some(binner);
|
||||
}
|
||||
let binner = self.binner.as_mut().unwrap();
|
||||
trace2!("process_item call binner ingest");
|
||||
binner.ingest(&mut item);
|
||||
}
|
||||
|
||||
fn handle_data_item(
|
||||
&mut self,
|
||||
item: T,
|
||||
) -> Result<ControlFlow<Poll<Sitemty<<<T as TimeBinnableTy>::TimeBinner as TimeBinnerTy>::Output>>>, Error> {
|
||||
use ControlFlow::*;
|
||||
use Poll::*;
|
||||
trace2!("================= handle_data_item");
|
||||
let item_len = item.len();
|
||||
self.process_item(item);
|
||||
let mut do_emit = false;
|
||||
if self.done_first_input == false {
|
||||
debug!(
|
||||
"emit container after the first input len {} binner {}",
|
||||
item_len,
|
||||
self.binner.is_some()
|
||||
);
|
||||
if self.binner.is_none() {
|
||||
let e = Error::with_msg_no_trace("must emit on first input but no binner");
|
||||
self.done = true;
|
||||
return Err(e);
|
||||
}
|
||||
do_emit = true;
|
||||
self.done_first_input = true;
|
||||
}
|
||||
if let Some(binner) = self.binner.as_mut() {
|
||||
trace3!("bins ready count {}", binner.bins_ready_count());
|
||||
if binner.bins_ready_count() > 0 {
|
||||
do_emit = true
|
||||
}
|
||||
if do_emit {
|
||||
if let Some(bins) = binner.bins_ready() {
|
||||
Ok(Break(Ready(sitem_data(bins))))
|
||||
} else {
|
||||
if let Some(bins) = binner.empty() {
|
||||
Ok(Break(Ready(sitem_data(bins))))
|
||||
} else {
|
||||
let e = Error::with_msg_no_trace("must emit but can not even create empty A");
|
||||
error!("{e}");
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
trace3!("not emit");
|
||||
Ok(ControlFlow::Continue(()))
|
||||
}
|
||||
} else {
|
||||
warn!("processed item, but no binner yet");
|
||||
Ok(ControlFlow::Continue(()))
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_item(
|
||||
&mut self,
|
||||
item: Result<StreamItem<RangeCompletableItem<T>>, Error>,
|
||||
) -> Result<ControlFlow<Poll<Sitemty<<<T as TimeBinnableTy>::TimeBinner as TimeBinnerTy>::Output>>>, Error> {
|
||||
use ControlFlow::*;
|
||||
use Poll::*;
|
||||
trace2!("================= handle_item");
|
||||
match item {
|
||||
Ok(item) => match item {
|
||||
StreamItem::DataItem(item) => match item {
|
||||
RangeCompletableItem::RangeComplete => {
|
||||
debug!("see RangeComplete");
|
||||
self.range_final = true;
|
||||
Ok(Continue(()))
|
||||
}
|
||||
RangeCompletableItem::Data(item) => self.handle_data_item(item),
|
||||
},
|
||||
StreamItem::Log(item) => Ok(Break(Ready(Ok(StreamItem::Log(item))))),
|
||||
StreamItem::Stats(item) => Ok(Break(Ready(Ok(StreamItem::Stats(item))))),
|
||||
},
|
||||
Err(e) => {
|
||||
error!("received error item: {e}");
|
||||
self.done = true;
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_none(
|
||||
&mut self,
|
||||
) -> Result<ControlFlow<Poll<Sitemty<<<T as TimeBinnableTy>::TimeBinner as TimeBinnerTy>::Output>>>, Error> {
|
||||
use ControlFlow::*;
|
||||
use Poll::*;
|
||||
trace2!("================= handle_none");
|
||||
let self_range_final = self.range_final;
|
||||
if let Some(binner) = self.binner.as_mut() {
|
||||
trace!("bins ready count before finish {}", binner.bins_ready_count());
|
||||
// TODO rework the finish logic
|
||||
if self_range_final {
|
||||
binner.set_range_complete();
|
||||
}
|
||||
binner.push_in_progress(false);
|
||||
trace!("bins ready count after finish {}", binner.bins_ready_count());
|
||||
if let Some(bins) = binner.bins_ready() {
|
||||
self.done_data = true;
|
||||
Ok(Break(Ready(sitem_data(bins))))
|
||||
} else {
|
||||
if let Some(bins) = binner.empty() {
|
||||
self.done_data = true;
|
||||
Ok(Break(Ready(sitem_data(bins))))
|
||||
} else {
|
||||
let e = Error::with_msg_no_trace("must emit but can not even create empty B");
|
||||
error!("{e}");
|
||||
self.done_data = true;
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warn!("input stream finished, still no binner");
|
||||
self.done_data = true;
|
||||
let e = Error::with_msg_no_trace(format!("input stream finished, still no binner"));
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
// Original block inside the poll loop was able to:
|
||||
// continue
|
||||
// break with Poll<Option<Item>>
|
||||
fn poll_input(
|
||||
&mut self,
|
||||
cx: &mut Context,
|
||||
) -> Result<ControlFlow<Poll<Sitemty<<<T as TimeBinnableTy>::TimeBinner as TimeBinnerTy>::Output>>>, Error> {
|
||||
use ControlFlow::*;
|
||||
use Poll::*;
|
||||
trace2!("================= poll_input");
|
||||
match self.inp.poll_next_unpin(cx) {
|
||||
Ready(Some(item)) => self.handle_item(item),
|
||||
Ready(None) => self.handle_none(),
|
||||
Pending => Ok(Break(Pending)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Stream for TimeBinnedStream<T>
|
||||
where
|
||||
T: TimeBinnableTy + Unpin,
|
||||
{
|
||||
type Item = Sitemty<<<T as TimeBinnableTy>::TimeBinner as TimeBinnerTy>::Output>;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
|
||||
use Poll::*;
|
||||
let span = span!(Level::INFO, "TimeBinner");
|
||||
let _spg = span.enter();
|
||||
trace2!("================= POLL");
|
||||
loop {
|
||||
break if self.complete {
|
||||
panic!("TimeBinnedStream poll on complete")
|
||||
} else if self.done {
|
||||
self.complete = true;
|
||||
Ready(None)
|
||||
} else if self.done_data {
|
||||
self.done = true;
|
||||
if self.range_final {
|
||||
Ready(Some(Ok(StreamItem::DataItem(RangeCompletableItem::RangeComplete))))
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
match self.poll_input(cx) {
|
||||
Ok(item) => match item {
|
||||
ControlFlow::Continue(()) => continue,
|
||||
ControlFlow::Break(item) => match item {
|
||||
Ready(item) => break Ready(Some(item)),
|
||||
Pending => break Pending,
|
||||
},
|
||||
},
|
||||
Err(e) => {
|
||||
self.done = true;
|
||||
break Ready(Some(Err(e)));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//impl<T> WithTransformProperties for TimeBinnedStream<T> where T: TimeBinnableTy {}
|
||||
|
||||
//impl<T> TimeBinnableStreamTrait for TimeBinnedStream<T> where T: TimeBinnableTy {}
|
||||
4
crates/streams/src/timebin/cached.rs
Normal file
4
crates/streams/src/timebin/cached.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
// mods for:
|
||||
// time-binned at any resolution.
|
||||
|
||||
pub mod reader;
|
||||
30
crates/streams/src/timebin/cached/reader.rs
Normal file
30
crates/streams/src/timebin/cached/reader.rs
Normal file
@@ -0,0 +1,30 @@
|
||||
use err::thiserror;
|
||||
use err::ThisError;
|
||||
use futures_util::Stream;
|
||||
use items_2::binsdim0::BinsDim0;
|
||||
use netpod::BinnedRange;
|
||||
use netpod::DtMs;
|
||||
use netpod::TsNano;
|
||||
use std::pin::Pin;
|
||||
use std::task::Context;
|
||||
use std::task::Poll;
|
||||
|
||||
#[derive(Debug, ThisError)]
|
||||
#[cstm(name = "BinCachedReader")]
|
||||
pub enum Error {}
|
||||
|
||||
pub struct CachedReader {}
|
||||
|
||||
impl CachedReader {
|
||||
pub fn new(series: u64, bin_len: DtMs, range: BinnedRange<TsNano>) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream for CachedReader {
|
||||
type Item = Result<BinsDim0<f32>, Error>;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
101
crates/streams/src/timebin/fromlayers.rs
Normal file
101
crates/streams/src/timebin/fromlayers.rs
Normal file
@@ -0,0 +1,101 @@
|
||||
use crate::timebin::grid::find_next_finer_bin_len;
|
||||
use err::thiserror;
|
||||
use err::ThisError;
|
||||
use futures_util::Stream;
|
||||
use futures_util::StreamExt;
|
||||
use futures_util::TryStreamExt;
|
||||
use items_0::streamitem::RangeCompletableItem;
|
||||
use items_0::streamitem::Sitemty;
|
||||
use items_0::streamitem::StreamItem;
|
||||
use items_0::timebin::TimeBinnableTy;
|
||||
use items_2::binsdim0::BinsDim0;
|
||||
use netpod::log::*;
|
||||
use netpod::BinnedRange;
|
||||
use netpod::BinnedRangeEnum;
|
||||
use netpod::DtMs;
|
||||
use netpod::TsNano;
|
||||
use std::pin::Pin;
|
||||
use std::task::Context;
|
||||
use std::task::Poll;
|
||||
|
||||
#[derive(Debug, ThisError)]
|
||||
#[cstm(name = "TimeBinnedFromLayers")]
|
||||
pub enum Error {
|
||||
Logic,
|
||||
GapFill(#[from] super::gapfill::Error),
|
||||
}
|
||||
|
||||
type BoxedInput = Pin<Box<dyn Stream<Item = Sitemty<BinsDim0<f32>>> + Send>>;
|
||||
|
||||
pub struct TimeBinnedFromLayers {
|
||||
inp: BoxedInput,
|
||||
}
|
||||
|
||||
impl TimeBinnedFromLayers {
|
||||
pub fn type_name() -> &'static str {
|
||||
core::any::type_name::<Self>()
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
series: u64,
|
||||
range: BinnedRange<TsNano>,
|
||||
do_time_weight: bool,
|
||||
bin_len_layers: Vec<DtMs>,
|
||||
) -> Result<Self, Error> {
|
||||
info!(
|
||||
"{}::new {:?} {:?} {:?}",
|
||||
Self::type_name(),
|
||||
series,
|
||||
range,
|
||||
bin_len_layers
|
||||
);
|
||||
// cases:
|
||||
// if this bin_len is a cachable bin_len:
|
||||
// - have to attempt to read from cache.
|
||||
// expect to read bins in a stream (randomize to small max len for testing).
|
||||
// also, if this bin_len is a cachable bin_len:
|
||||
// must produce bins missing in cache from separate stream.
|
||||
let bin_len = DtMs::from_ms_u64(range.bin_len.ms());
|
||||
if bin_len_layers.contains(&bin_len) {
|
||||
let inp = super::gapfill::GapFill::new(series, bin_len, range)?;
|
||||
let ret = Self { inp: Box::pin(inp) };
|
||||
Ok(ret)
|
||||
} else {
|
||||
match find_next_finer_bin_len(bin_len, &bin_len_layers) {
|
||||
Some(finer) => {
|
||||
// TODO
|
||||
// produce from binned sub-stream with additional binner.
|
||||
let inp = super::gapfill::GapFill::new(series, bin_len, range.clone())?
|
||||
// .map(|item| {
|
||||
// let ret = match item {
|
||||
// Ok(k) => Ok(StreamItem::DataItem(RangeCompletableItem::Data(k))),
|
||||
// Err(e) => Err(::err::Error::from_string(e)),
|
||||
// };
|
||||
// ret
|
||||
// })
|
||||
;
|
||||
let inp = super::basic::TimeBinnedStream::new(
|
||||
Box::pin(inp),
|
||||
BinnedRangeEnum::Time(range),
|
||||
do_time_weight,
|
||||
);
|
||||
let ret = Self { inp: Box::pin(inp) };
|
||||
Ok(ret)
|
||||
}
|
||||
None => {
|
||||
// TODO
|
||||
// produce from events
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream for TimeBinnedFromLayers {
|
||||
type Item = Sitemty<BinsDim0<f32>>;
|
||||
|
||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
49
crates/streams/src/timebin/gapfill.rs
Normal file
49
crates/streams/src/timebin/gapfill.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
use err::thiserror;
|
||||
use err::ThisError;
|
||||
use futures_util::Stream;
|
||||
use items_0::streamitem::Sitemty;
|
||||
use items_2::binsdim0::BinsDim0;
|
||||
use netpod::BinnedRange;
|
||||
use netpod::DtMs;
|
||||
use netpod::TsNano;
|
||||
use std::pin::Pin;
|
||||
use std::task::Context;
|
||||
use std::task::Poll;
|
||||
|
||||
#[derive(Debug, ThisError)]
|
||||
#[cstm(name = "BinCachedGapFill")]
|
||||
pub enum Error {}
|
||||
|
||||
// Try to read from cache for the given bin len.
|
||||
// For gaps in the stream, construct an alternative input from finer bin len with a binner.
|
||||
pub struct GapFill {}
|
||||
|
||||
impl GapFill {
|
||||
pub fn new(series: u64, bin_len: DtMs, range: BinnedRange<TsNano>) -> Result<Self, Error> {
|
||||
// TODO assert that the requested bin_len is a cacheable length.
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream for GapFill {
|
||||
type Item = Sitemty<BinsDim0<f32>>;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
|
||||
// When do we detect a gap:
|
||||
// - when the current item poses a gap to the last.
|
||||
// - when we see EOS before the requested range is filled.
|
||||
// Requirements:
|
||||
// Must always request fully cache-aligned ranges.
|
||||
// Must remember where the last bin ended.
|
||||
|
||||
// When a gap is detected:
|
||||
// - buffer the current item, if there is one (can also be EOS).
|
||||
// - create a new producer of bin:
|
||||
// - FromFiner(series, bin_len, range)
|
||||
// what does FromFiner bring to the table?
|
||||
// It does not attempt to read the given bin-len from a cache, because we just did attempt that.
|
||||
// It still requires that bin-len is cacheable. (NO! it must work with the layering that I passed!)
|
||||
// Then it finds the next cacheable
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
7
crates/streams/src/timebin/grid.rs
Normal file
7
crates/streams/src/timebin/grid.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
use netpod::DtMs;
|
||||
|
||||
// Find the next finer bin len from the passed list.
|
||||
// The list is assumed to be sorted ascending, meaning finer bin len first.
|
||||
pub fn find_next_finer_bin_len(bin_len: DtMs, layers: &[DtMs]) -> Option<DtMs> {
|
||||
todo!("find_next_finer_bin_len")
|
||||
}
|
||||
@@ -12,7 +12,9 @@ use futures_util::Stream;
|
||||
use futures_util::StreamExt;
|
||||
use items_0::collect_s::Collectable;
|
||||
use items_0::on_sitemty_data;
|
||||
use items_0::streamitem::RangeCompletableItem;
|
||||
use items_0::streamitem::Sitemty;
|
||||
use items_0::streamitem::StreamItem;
|
||||
use items_0::timebin::TimeBinned;
|
||||
use items_0::transform::TimeBinnableStreamBox;
|
||||
use items_0::transform::TimeBinnableStreamTrait;
|
||||
@@ -21,9 +23,11 @@ use items_2::channelevents::ChannelEvents;
|
||||
use items_2::merger::Merger;
|
||||
use items_2::streams::PlainEventStream;
|
||||
use netpod::log::*;
|
||||
use netpod::log::*;
|
||||
use netpod::range::evrange::NanoRange;
|
||||
use netpod::BinnedRangeEnum;
|
||||
use netpod::ChannelTypeConfigGen;
|
||||
use netpod::DtMs;
|
||||
use netpod::ReqCtx;
|
||||
use query::api4::binned::BinnedQuery;
|
||||
use serde_json::Value as JsonValue;
|
||||
@@ -224,18 +228,78 @@ async fn timebinned_stream(
|
||||
ctx: &ReqCtx,
|
||||
open_bytes: OpenBoxedBytesStreamsBox,
|
||||
) -> Result<Pin<Box<dyn Stream<Item = Sitemty<Box<dyn TimeBinned>>> + Send>>, Error> {
|
||||
let range = binned_range.binned_range_time().to_nano_range();
|
||||
use netpod::query::CacheUsage;
|
||||
match query.cache_usage() {
|
||||
CacheUsage::Use | CacheUsage::Recreate => {
|
||||
let series = if let Some(x) = query.channel().series() {
|
||||
x
|
||||
} else {
|
||||
return Err(Error::with_msg_no_trace(
|
||||
"cached time binned only available given a series id",
|
||||
));
|
||||
};
|
||||
info!("--- CACHING PATH ---");
|
||||
info!("{query:?}");
|
||||
info!("subgrids {:?}", query.subgrids());
|
||||
let range = binned_range.binned_range_time().to_nano_range();
|
||||
let do_time_weight = true;
|
||||
let bin_len_layers = if let Some(subgrids) = query.subgrids() {
|
||||
subgrids
|
||||
.iter()
|
||||
.map(|&x| DtMs::from_ms_u64(1000 * x.as_secs()))
|
||||
.collect()
|
||||
} else {
|
||||
vec![
|
||||
DtMs::from_ms_u64(1000 * 60),
|
||||
// DtMs::from_ms_u64(1000 * 60 * 60),
|
||||
// DtMs::from_ms_u64(1000 * 60 * 60 * 12),
|
||||
// DtMs::from_ms_u64(1000 * 10),
|
||||
]
|
||||
};
|
||||
let stream = crate::timebin::TimeBinnedFromLayers::new(
|
||||
series,
|
||||
binned_range.binned_range_time(),
|
||||
do_time_weight,
|
||||
bin_len_layers,
|
||||
)
|
||||
.map_err(Error::from_string)?;
|
||||
// Possible to simplify these kind of seemingly simple type conversions?
|
||||
let stream = stream.map(|item| match item {
|
||||
Ok(StreamItem::DataItem(RangeCompletableItem::Data(k))) => Ok(StreamItem::DataItem(
|
||||
RangeCompletableItem::Data(Box::new(k) as Box<dyn TimeBinned>),
|
||||
)),
|
||||
Ok(StreamItem::DataItem(RangeCompletableItem::RangeComplete)) => {
|
||||
Ok(StreamItem::DataItem(RangeCompletableItem::RangeComplete))
|
||||
}
|
||||
Ok(StreamItem::Log(k)) => Ok(StreamItem::Log(k)),
|
||||
Ok(StreamItem::Stats(k)) => Ok(StreamItem::Stats(k)),
|
||||
Err(e) => Err(e),
|
||||
});
|
||||
// let stream = stream.map(|item| match item {
|
||||
// Ok(k) => {
|
||||
// let k = Box::new(k) as Box<dyn TimeBinned>;
|
||||
// Ok(StreamItem::DataItem(RangeCompletableItem::Data(k)))
|
||||
// }
|
||||
// Err(e) => Err(::err::Error::from_string(e)),
|
||||
// });
|
||||
let stream: Pin<Box<dyn Stream<Item = Sitemty<Box<dyn TimeBinned>>> + Send>> = Box::pin(stream);
|
||||
Ok(stream)
|
||||
}
|
||||
CacheUsage::Ignore => {
|
||||
let range = binned_range.binned_range_time().to_nano_range();
|
||||
|
||||
let do_time_weight = true;
|
||||
let one_before_range = true;
|
||||
let do_time_weight = true;
|
||||
let one_before_range = true;
|
||||
|
||||
let stream = timebinnable_stream(query.clone(), range, one_before_range, ch_conf, ctx, open_bytes).await?;
|
||||
let stream: Pin<Box<dyn TimeBinnableStreamTrait>> = stream.0;
|
||||
let stream = Box::pin(stream);
|
||||
// TODO rename TimeBinnedStream to make it more clear that it is the component which initiates the time binning.
|
||||
let stream = TimeBinnedStream::new(stream, binned_range, do_time_weight);
|
||||
let stream: Pin<Box<dyn Stream<Item = Sitemty<Box<dyn TimeBinned>>> + Send>> = Box::pin(stream);
|
||||
Ok(stream)
|
||||
let stream = timebinnable_stream(query.clone(), range, one_before_range, ch_conf, ctx, open_bytes).await?;
|
||||
let stream: Pin<Box<dyn TimeBinnableStreamTrait>> = stream.0;
|
||||
let stream = Box::pin(stream);
|
||||
// TODO rename TimeBinnedStream to make it more clear that it is the component which initiates the time binning.
|
||||
let stream = TimeBinnedStream::new(stream, binned_range, do_time_weight);
|
||||
let stream: Pin<Box<dyn Stream<Item = Sitemty<Box<dyn TimeBinned>>> + Send>> = Box::pin(stream);
|
||||
Ok(stream)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn timebinned_to_collectable(
|
||||
@@ -268,6 +332,16 @@ pub async fn timebinned_json(
|
||||
let collected = Collect::new(stream, deadline, collect_max, bytes_max, None, Some(binned_range));
|
||||
let collected: BoxFuture<_> = Box::pin(collected);
|
||||
let collected = collected.await?;
|
||||
info!("timebinned_json collected type_name {:?}", collected.type_name());
|
||||
let collected = if let Some(bins) = collected
|
||||
.as_any_ref()
|
||||
.downcast_ref::<items_2::binsdim0::BinsDim0CollectedResult<netpod::EnumVariant>>()
|
||||
{
|
||||
info!("MATCHED");
|
||||
bins.boxed_collected_with_enum_fix()
|
||||
} else {
|
||||
collected
|
||||
};
|
||||
let jsval = serde_json::to_value(&collected)?;
|
||||
Ok(jsval)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user