From 8c55bf7de7c6b82018cdc241c072da2188600fa4 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 6 Aug 2020 17:51:57 -0700 Subject: [PATCH] SharedPV monitor discard empty updates --- src/pvrequest.cpp | 20 ++++++++++++++++++++ src/pvrequest.h | 3 +++ src/servermon.cpp | 30 ++++++++++++++++-------------- test/testpvreq.cpp | 33 ++++++++++++++++++++++++++++++++- 4 files changed, 71 insertions(+), 15 deletions(-) diff --git a/src/pvrequest.cpp b/src/pvrequest.cpp index 6cc4b59..decee8f 100644 --- a/src/pvrequest.cpp +++ b/src/pvrequest.cpp @@ -71,5 +71,25 @@ BitMask request2mask(const FieldDesc* desc, const Value& pvRequest) return ret; } +bool testmask(const Value& update, const BitMask& mask) +{ + auto desc = Value::Helper::desc(update); + auto store = Value::Helper::store_ptr(update); + + if(!desc) + return false; + + if(store->valid && mask[0]) + return true; + + if(desc->code==TypeCode::Struct) { + for(auto idx : range(size_t(1u), desc->size())) { + if(store[idx].valid && mask[idx]) + return true; + } + } + + return false; +} }} // namespace pvxs::impl diff --git a/src/pvrequest.h b/src/pvrequest.h index d893c8d..19d9ca9 100644 --- a/src/pvrequest.h +++ b/src/pvrequest.h @@ -16,6 +16,9 @@ namespace impl { PVXS_API BitMask request2mask(const FieldDesc* desc, const Value& pvRequest); +PVXS_API +bool testmask(const Value& update, const BitMask& mask); + }} // namespace pvxs::impl #endif // PVREQUEST_H diff --git a/src/servermon.cpp b/src/servermon.cpp index c56c164..db74b07 100644 --- a/src/servermon.cpp +++ b/src/servermon.cpp @@ -220,28 +220,30 @@ struct ServerMonitorControl : public server::MonitorControlOp if(!mon) return false; - Guard G(mon->lock); - if(val && mon->type && mon->type.get()!=Value::Helper::desc(val)) throw std::logic_error("Type change not allowed in post(). Recommend pvxs::Value::cloneEmpty()"); - if((mon->queue.size() < mon->limit) || force || !val) { - mon->queue.push_back(val); + if(testmask(val, mon->pvMask)) { + Guard G(mon->lock); - } else if(!maybe) { - // squash - assert(mon->limit>0 && !mon->queue.empty()); + if((mon->queue.size() < mon->limit) || force || !val) { + mon->queue.push_back(val); - mon->queue.back().assign(val); - // TODO track overrun + } else if(!maybe) { + // squash + assert(mon->limit>0 && !mon->queue.empty()); - } else { - // nope + mon->queue.back().assign(val); + // TODO track overrun + + } else { + // nope + } + + if(auto serv = server.lock()) + MonitorOp::maybeReply(serv.get(), mon); } - if(auto serv = server.lock()) - MonitorOp::maybeReply(serv.get(), mon); - return mon->queue.size() < mon->limit; } diff --git a/test/testpvreq.cpp b/test/testpvreq.cpp index df51db2..57c4cec 100644 --- a/test/testpvreq.cpp +++ b/test/testpvreq.cpp @@ -71,6 +71,36 @@ void testPvRequest() } } +void testPvMask() +{ + auto val = nt::NTScalar{TypeCode::String}.create(); + + auto rdef = TypeDef(TypeCode::Struct, { + members::Struct("field", { + members::Struct("value", {}), + }) + }); + + auto mask = request2mask(Value::Helper::desc(val), rdef.create()); + + testFalse(testmask(val, mask)); + + val["alarm.status"].mark(); + testFalse(testmask(val, mask)); + + val["value"].mark(); + testTrue(testmask(val, mask)); + + val["alarm.status"].unmark(); + testTrue(testmask(val, mask)); + + val.unmark(); + testFalse(testmask(val, mask)); + + val.mark(); + testTrue(testmask(val, mask)); +} + struct TestBuilder : client::detail::CommonBuilder { TestBuilder() @@ -349,10 +379,11 @@ void testArgs() MAIN(testpvreq) { - testPlan(30); + testPlan(36); testSetup(); logger_config_env(); testPvRequest(); + testPvMask(); testEmpty(); testAssemble(); testParseEmpty();