Add handler for accounting and refactor
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
use crate::errconv::ErrConv;
|
||||
use err::Error;
|
||||
use futures_util::Future;
|
||||
use futures_util::FutureExt;
|
||||
use futures_util::Stream;
|
||||
use items_0::Empty;
|
||||
use items_0::Extendable;
|
||||
use items_0::WithLen;
|
||||
use items_2::accounting::AccountingEvents;
|
||||
use netpod::log::*;
|
||||
use netpod::range::evrange::NanoRange;
|
||||
use netpod::timeunits;
|
||||
use netpod::EMIT_ACCOUNTING_SNAP;
|
||||
use scylla::Session as ScySession;
|
||||
use std::collections::VecDeque;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use std::task::Context;
|
||||
use std::task::Poll;
|
||||
|
||||
async fn read_next(ts_msp: u64, range: NanoRange, fwd: bool, scy: Arc<ScySession>) -> Result<AccountingEvents, Error> {
|
||||
if ts_msp >= range.end {
|
||||
warn!(
|
||||
"given ts_msp {} >= range.end {} not necessary to read this",
|
||||
ts_msp, range.end
|
||||
);
|
||||
}
|
||||
if range.end > i64::MAX as u64 {
|
||||
return Err(Error::with_msg_no_trace(format!("range.end overflows i64")));
|
||||
}
|
||||
let mut ret = AccountingEvents::empty();
|
||||
let mut tot_bytes = 0;
|
||||
for part in 0..255_u32 {
|
||||
let res = if fwd {
|
||||
let ts_lsp_min = if ts_msp < range.beg { range.beg - ts_msp } else { 0 };
|
||||
let ts_lsp_max = if ts_msp < range.end { range.end - ts_msp } else { 0 };
|
||||
trace!(
|
||||
"FWD ts_msp {} ts_lsp_min {} ts_lsp_max {} beg {} end {}",
|
||||
ts_msp,
|
||||
ts_lsp_min,
|
||||
ts_lsp_max,
|
||||
range.beg,
|
||||
range.end
|
||||
);
|
||||
// TODO use prepared!
|
||||
let cql = concat!("select series, count, bytes from account_00 where part = ? and ts = ?");
|
||||
scy.query(cql, (part as i32, ts_msp as i64)).await.err_conv()?
|
||||
} else {
|
||||
return Err(Error::with_msg_no_trace("no backward support"));
|
||||
};
|
||||
type RowType = (i64, i64, i64);
|
||||
for row in res.rows_typed_or_empty::<RowType>() {
|
||||
let row = row.err_conv()?;
|
||||
let ts = ts_msp;
|
||||
let series = row.0 as u64;
|
||||
let count = row.1 as u64;
|
||||
let bytes = row.1 as u64;
|
||||
tot_bytes += bytes;
|
||||
}
|
||||
}
|
||||
ret.tss.push_back(ts_msp);
|
||||
ret.bytes.push_back(tot_bytes);
|
||||
trace!("found in total {} events ts_msp {}", ret.len(), ts_msp);
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
struct ReadValues {
|
||||
series: u64,
|
||||
range: NanoRange,
|
||||
ts_msps: VecDeque<u64>,
|
||||
fwd: bool,
|
||||
do_one_before_range: bool,
|
||||
fut: Pin<Box<dyn Future<Output = Result<AccountingEvents, Error>> + Send>>,
|
||||
scy: Arc<ScySession>,
|
||||
}
|
||||
|
||||
impl ReadValues {
|
||||
fn new(
|
||||
series: u64,
|
||||
range: NanoRange,
|
||||
ts_msps: VecDeque<u64>,
|
||||
fwd: bool,
|
||||
do_one_before_range: bool,
|
||||
scy: Arc<ScySession>,
|
||||
) -> Self {
|
||||
let mut ret = Self {
|
||||
series,
|
||||
range,
|
||||
ts_msps,
|
||||
fwd,
|
||||
do_one_before_range,
|
||||
fut: Box::pin(futures_util::future::ready(Err(Error::with_msg_no_trace(
|
||||
"future not initialized",
|
||||
)))),
|
||||
scy,
|
||||
};
|
||||
ret.next();
|
||||
ret
|
||||
}
|
||||
|
||||
fn next(&mut self) -> bool {
|
||||
if let Some(ts_msp) = self.ts_msps.pop_front() {
|
||||
self.fut = self.make_fut(ts_msp);
|
||||
true
|
||||
} else {
|
||||
debug!("no more msp");
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn make_fut(&mut self, ts_msp: u64) -> Pin<Box<dyn Future<Output = Result<AccountingEvents, Error>> + Send>> {
|
||||
debug!("make fut for {ts_msp}");
|
||||
let fut = read_next(ts_msp, self.range.clone(), self.fwd, self.scy.clone());
|
||||
Box::pin(fut)
|
||||
}
|
||||
}
|
||||
|
||||
enum FrState {
|
||||
New,
|
||||
ReadValues(ReadValues),
|
||||
Done,
|
||||
}
|
||||
|
||||
pub struct AccountingStreamScylla {
|
||||
state: FrState,
|
||||
series: u64,
|
||||
range: NanoRange,
|
||||
scy: Arc<ScySession>,
|
||||
outbuf: AccountingEvents,
|
||||
}
|
||||
|
||||
impl AccountingStreamScylla {
|
||||
pub fn new(series: u64, range: NanoRange, scy: Arc<ScySession>) -> Self {
|
||||
Self {
|
||||
state: FrState::New,
|
||||
series,
|
||||
range,
|
||||
scy,
|
||||
outbuf: AccountingEvents::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream for AccountingStreamScylla {
|
||||
type Item = Result<AccountingEvents, Error>;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
|
||||
use Poll::*;
|
||||
let span = tracing::span!(tracing::Level::TRACE, "poll_next");
|
||||
let _spg = span.enter();
|
||||
loop {
|
||||
if self.outbuf.len() > 0 {
|
||||
let item = std::mem::replace(&mut self.outbuf, AccountingEvents::empty());
|
||||
break Ready(Some(Ok(item)));
|
||||
}
|
||||
break match self.state {
|
||||
FrState::New => {
|
||||
let mut ts_msps = VecDeque::new();
|
||||
let mut ts = self.range.beg / timeunits::SEC / EMIT_ACCOUNTING_SNAP * EMIT_ACCOUNTING_SNAP;
|
||||
while ts < self.range.end {
|
||||
debug!("use ts {ts}");
|
||||
ts_msps.push_back(ts);
|
||||
ts += EMIT_ACCOUNTING_SNAP;
|
||||
}
|
||||
let fwd = true;
|
||||
let do_one_before_range = false;
|
||||
let st = ReadValues::new(
|
||||
self.series,
|
||||
self.range.clone(),
|
||||
ts_msps,
|
||||
fwd,
|
||||
do_one_before_range,
|
||||
self.scy.clone(),
|
||||
);
|
||||
self.state = FrState::ReadValues(st);
|
||||
continue;
|
||||
}
|
||||
FrState::ReadValues(ref mut st) => match st.fut.poll_unpin(cx) {
|
||||
Ready(Ok(mut item)) => {
|
||||
if !st.next() {
|
||||
debug!("ReadValues exhausted");
|
||||
self.state = FrState::Done;
|
||||
}
|
||||
self.outbuf.extend_from(&mut item);
|
||||
continue;
|
||||
}
|
||||
Ready(Err(e)) => {
|
||||
error!("{e}");
|
||||
Ready(Some(Err(e)))
|
||||
}
|
||||
Pending => Pending,
|
||||
},
|
||||
FrState::Done => Ready(None),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
use crate::errconv::ErrConv;
|
||||
use err::Error;
|
||||
use netpod::ScyllaConfig;
|
||||
use scylla::execution_profile::ExecutionProfileBuilder;
|
||||
use scylla::statement::Consistency;
|
||||
use scylla::Session as ScySession;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub async fn create_scy_session(scyconf: &ScyllaConfig) -> Result<Arc<ScySession>, Error> {
|
||||
let scy = scylla::SessionBuilder::new()
|
||||
.known_nodes(&scyconf.hosts)
|
||||
.use_keyspace(&scyconf.keyspace, true)
|
||||
.default_execution_profile_handle(
|
||||
ExecutionProfileBuilder::default()
|
||||
.consistency(Consistency::LocalOne)
|
||||
.build()
|
||||
.into_handle(),
|
||||
)
|
||||
.build()
|
||||
.await
|
||||
.err_conv()?;
|
||||
let ret = Arc::new(scy);
|
||||
Ok(ret)
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::errconv::ErrConv;
|
||||
use crate::ScyllaSeriesRange;
|
||||
use crate::range::ScyllaSeriesRange;
|
||||
use err::Error;
|
||||
use futures_util::Future;
|
||||
use futures_util::FutureExt;
|
||||
@@ -33,14 +33,14 @@ async fn find_ts_msp(
|
||||
let mut ret2 = VecDeque::new();
|
||||
// TODO use prepared statements
|
||||
let cql = "select ts_msp from ts_msp where series = ? and ts_msp < ? order by ts_msp desc limit 2";
|
||||
let res = scy.query(cql, (series as i64, range.beg as i64)).await.err_conv()?;
|
||||
let res = scy.query(cql, (series as i64, range.beg() as i64)).await.err_conv()?;
|
||||
for row in res.rows_typed_or_empty::<(i64,)>() {
|
||||
let row = row.err_conv()?;
|
||||
ret1.push_front(row.0 as u64);
|
||||
}
|
||||
let cql = "select ts_msp from ts_msp where series = ? and ts_msp >= ? and ts_msp < ?";
|
||||
let res = scy
|
||||
.query(cql, (series as i64, range.beg as i64, range.end as i64))
|
||||
.query(cql, (series as i64, range.beg() as i64, range.end() as i64))
|
||||
.await
|
||||
.err_conv()?;
|
||||
for row in res.rows_typed_or_empty::<(i64,)>() {
|
||||
@@ -48,7 +48,7 @@ async fn find_ts_msp(
|
||||
ret2.push_back(row.0 as u64);
|
||||
}
|
||||
let cql = "select ts_msp from ts_msp where series = ? and ts_msp >= ? limit 1";
|
||||
let res = scy.query(cql, (series as i64, range.end as i64)).await.err_conv()?;
|
||||
let res = scy.query(cql, (series as i64, range.end() as i64)).await.err_conv()?;
|
||||
for row in res.rows_typed_or_empty::<(i64,)>() {
|
||||
let row = row.err_conv()?;
|
||||
ret2.push_back(row.0 as u64);
|
||||
@@ -149,7 +149,7 @@ where
|
||||
let fwd = opts.fwd;
|
||||
let scy = opts.scy;
|
||||
let table_name = ST::table_name();
|
||||
if range.end > i64::MAX as u64 {
|
||||
if range.end() > i64::MAX as u64 {
|
||||
return Err(Error::with_msg_no_trace(format!("range.end overflows i64")));
|
||||
}
|
||||
let cql_fields = if opts.with_values {
|
||||
@@ -158,15 +158,15 @@ where
|
||||
"ts_lsp, pulse"
|
||||
};
|
||||
let ret = if fwd {
|
||||
let ts_lsp_min = if ts_msp < range.beg { range.beg - ts_msp } else { 0 };
|
||||
let ts_lsp_max = if ts_msp < range.end { range.end - ts_msp } else { 0 };
|
||||
let ts_lsp_min = if ts_msp < range.beg() { range.beg() - ts_msp } else { 0 };
|
||||
let ts_lsp_max = if ts_msp < range.end() { range.end() - ts_msp } else { 0 };
|
||||
trace!(
|
||||
"FWD ts_msp {} ts_lsp_min {} ts_lsp_max {} beg {} end {} {}",
|
||||
ts_msp,
|
||||
ts_lsp_min,
|
||||
ts_lsp_max,
|
||||
range.beg,
|
||||
range.end,
|
||||
range.beg(),
|
||||
range.end(),
|
||||
table_name,
|
||||
);
|
||||
// TODO use prepared!
|
||||
@@ -200,10 +200,10 @@ where
|
||||
let value = ValTy::default();
|
||||
(ts, pulse, value)
|
||||
};
|
||||
if ts >= range.end {
|
||||
if ts >= range.end() {
|
||||
// TODO count as logic error
|
||||
error!("ts >= range.end");
|
||||
} else if ts >= range.beg {
|
||||
} else if ts >= range.beg() {
|
||||
if pulse % 27 != 3618 {
|
||||
ret.push(ts, pulse, value);
|
||||
}
|
||||
@@ -216,13 +216,13 @@ where
|
||||
}
|
||||
ret
|
||||
} else {
|
||||
let ts_lsp_max = if ts_msp < range.beg { range.beg - ts_msp } else { 0 };
|
||||
let ts_lsp_max = if ts_msp < range.beg() { range.beg() - ts_msp } else { 0 };
|
||||
trace!(
|
||||
"BCK ts_msp {} ts_lsp_max {} beg {} end {} {}",
|
||||
ts_msp,
|
||||
ts_lsp_max,
|
||||
range.beg,
|
||||
range.end,
|
||||
range.beg(),
|
||||
range.end(),
|
||||
table_name,
|
||||
);
|
||||
// TODO use prepared!
|
||||
@@ -253,10 +253,10 @@ where
|
||||
let value = ValTy::default();
|
||||
(ts, pulse, value)
|
||||
};
|
||||
if ts >= range.beg {
|
||||
if ts >= range.beg() {
|
||||
// TODO count as logic error
|
||||
error!("ts >= range.beg");
|
||||
} else if ts < range.beg {
|
||||
} else if ts < range.beg() {
|
||||
if pulse % 27 != 3618 {
|
||||
ret.push(ts, pulse, value);
|
||||
}
|
||||
@@ -445,7 +445,7 @@ impl EventsStreamScylla {
|
||||
self.ts_msp_fwd = msps2;
|
||||
for x in self.ts_msp_bck.iter().rev() {
|
||||
let x = x.clone();
|
||||
if x >= self.range.end {
|
||||
if x >= self.range.end() {
|
||||
info!("FOUND one-after because of MSP");
|
||||
self.found_one_after = true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
use netpod::range::evrange::SeriesRange;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ScyllaSeriesRange {
|
||||
beg: u64,
|
||||
end: u64,
|
||||
}
|
||||
|
||||
impl ScyllaSeriesRange {
|
||||
pub fn beg(&self) -> u64 {
|
||||
self.beg
|
||||
}
|
||||
|
||||
pub fn end(&self) -> u64 {
|
||||
self.end
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&SeriesRange> for ScyllaSeriesRange {
|
||||
fn from(value: &SeriesRange) -> Self {
|
||||
match value {
|
||||
SeriesRange::TimeRange(k) => Self { beg: k.beg, end: k.end },
|
||||
SeriesRange::PulseRange(k) => Self { beg: k.beg, end: k.end },
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,47 +1,9 @@
|
||||
pub mod accounting;
|
||||
pub mod bincache;
|
||||
pub mod conn;
|
||||
pub mod errconv;
|
||||
pub mod events;
|
||||
pub mod range;
|
||||
pub mod status;
|
||||
|
||||
pub use scylla;
|
||||
|
||||
use err::Error;
|
||||
use errconv::ErrConv;
|
||||
use netpod::range::evrange::SeriesRange;
|
||||
use netpod::ScyllaConfig;
|
||||
use scylla::execution_profile::ExecutionProfileBuilder;
|
||||
use scylla::statement::Consistency;
|
||||
use scylla::Session as ScySession;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ScyllaSeriesRange {
|
||||
beg: u64,
|
||||
end: u64,
|
||||
}
|
||||
|
||||
impl From<&SeriesRange> for ScyllaSeriesRange {
|
||||
fn from(value: &SeriesRange) -> Self {
|
||||
match value {
|
||||
SeriesRange::TimeRange(k) => Self { beg: k.beg, end: k.end },
|
||||
SeriesRange::PulseRange(k) => Self { beg: k.beg, end: k.end },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn create_scy_session(scyconf: &ScyllaConfig) -> Result<Arc<ScySession>, Error> {
|
||||
let scy = scylla::SessionBuilder::new()
|
||||
.known_nodes(&scyconf.hosts)
|
||||
.use_keyspace(&scyconf.keyspace, true)
|
||||
.default_execution_profile_handle(
|
||||
ExecutionProfileBuilder::default()
|
||||
.consistency(Consistency::LocalOne)
|
||||
.build()
|
||||
.into_handle(),
|
||||
)
|
||||
.build()
|
||||
.await
|
||||
.err_conv()?;
|
||||
let ret = Arc::new(scy);
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
@@ -143,13 +143,13 @@ impl ReadValues {
|
||||
self.fut = self.make_fut(ts_msp);
|
||||
true
|
||||
} else {
|
||||
info!("no more msp");
|
||||
debug!("no more msp");
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn make_fut(&mut self, ts_msp: u64) -> Pin<Box<dyn Future<Output = Result<ChannelStatusEvents, Error>> + Send>> {
|
||||
info!("make fut for {ts_msp}");
|
||||
debug!("make fut for {ts_msp}");
|
||||
let fut = read_next_status_events(
|
||||
self.series,
|
||||
ts_msp,
|
||||
|
||||
Reference in New Issue
Block a user