diff --git a/lib/tdeck_ui/UI/LXMF/NomadNetCacheFlow.cpp b/lib/tdeck_ui/UI/LXMF/NomadNetCacheFlow.cpp index 33e1864d..00a40140 100644 --- a/lib/tdeck_ui/UI/LXMF/NomadNetCacheFlow.cpp +++ b/lib/tdeck_ui/UI/LXMF/NomadNetCacheFlow.cpp @@ -11,6 +11,7 @@ CacheFlowState NomadNetCacheFlow::begin(const CacheKey& key, std::uint64_t now, now_ = now; ExternalVector().swap(page_); status_ = reload ? "Invalidating cached page..." : "Checking page cache..."; + lookup_admitted_ = false; invalidation_admitted_ = false; if (reload) { state_ = CacheFlowState::INVALIDATE; @@ -19,9 +20,14 @@ CacheFlowState NomadNetCacheFlow::begin(const CacheKey& key, std::uint64_t now, } return state_; } - cache_.beginLookup(key_, now, false); - state_ = cache_.busy() ? CacheFlowState::LOOKUP : CacheFlowState::NEED_LIVE; - if (state_ == CacheFlowState::NEED_LIVE) status_ = "Requesting page..."; + state_ = CacheFlowState::LOOKUP; + if (!cache_.busy()) { + lookup_admitted_ = cache_.beginLookup(key_, now, false) == CacheResult::PENDING; + if (!lookup_admitted_) { + state_ = CacheFlowState::NEED_LIVE; + status_ = "Requesting page..."; + } + } return state_; } @@ -45,6 +51,14 @@ void NomadNetCacheFlow::service() { return; } if (state_ != CacheFlowState::LOOKUP || cache_.busy()) return; + if (!lookup_admitted_) { + lookup_admitted_ = cache_.beginLookup(key_, now_, false) == CacheResult::PENDING; + if (!lookup_admitted_) { + state_ = CacheFlowState::NEED_LIVE; + status_ = "Requesting page..."; + } + return; + } if (cache_.lastResult() == CacheResult::HIT && cache_.takeBody(page_)) { state_ = CacheFlowState::READY; status_ = "Cached page; current reachability not checked"; diff --git a/lib/tdeck_ui/UI/LXMF/NomadNetCacheFlow.h b/lib/tdeck_ui/UI/LXMF/NomadNetCacheFlow.h index 69c4e07e..90c171aa 100644 --- a/lib/tdeck_ui/UI/LXMF/NomadNetCacheFlow.h +++ b/lib/tdeck_ui/UI/LXMF/NomadNetCacheFlow.h @@ -38,6 +38,7 @@ private: ExternalVector page_; std::string status_; std::uint64_t now_ = 0; + bool lookup_admitted_ = false; bool invalidation_admitted_ = false; }; diff --git a/tests/native/test_nomadnet_cache_flow.cpp b/tests/native/test_nomadnet_cache_flow.cpp index e58a15c8..c802ad0d 100644 --- a/tests/native/test_nomadnet_cache_flow.cpp +++ b/tests/native/test_nomadnet_cache_flow.cpp @@ -8,6 +8,14 @@ struct Mem:NomadNetStorage{std::map>f;std::stri int main(){int f=0;auto ck=[&](bool x,const char*n){if(!x){f++;std::cerr<<"FAIL "<b={'o','k'};CacheEligibility e{true,true,false,false,false,false,RequestDataClass::NIL};ck(flow.acceptLive(b,e,100),"valid live accepted");ck(flow.pageReady()&&flow.status()=="Page loaded (live)","render ready before commit");for(int i=0;i<20;i++)flow.service(); NomadNetCacheFlow hit(c);ck(hit.begin(k,101,false)==CacheFlowState::LOOKUP,"second lookup");for(int i=0;i<10&&hit.state()==CacheFlowState::LOOKUP;i++)hit.service();ExternalVectorout;ck(hit.state()==CacheFlowState::READY&&hit.takePage(out)&&std::equal(out.begin(),out.end(),b.begin(),b.end())&&hit.status()=="Cached page; current reachability not checked","hit without peer and without internal-vector copy"); + // A new lookup arriving while unrelated cache work is active must wait for + // cancellation cleanup, admit its own lookup, and still use the available hit. + CacheKey other{"fedcba9876543210fedcba9876543210","/page/other.mu",RequestDataClass::NIL}; + ck(c.beginCommit(other,b,101,43200)==CacheResult::PENDING,"overlap commit admitted"); + NomadNetCacheFlow overlap(c);ck(overlap.begin(k,102,false)==CacheFlowState::LOOKUP,"overlap lookup waits"); + for(int i=0;i<200&&overlap.state()==CacheFlowState::LOOKUP;++i)overlap.service(); + ExternalVectoroverlap_out; + ck(overlap.state()==CacheFlowState::READY&&overlap.takePage(overlap_out)&&std::equal(overlap_out.begin(),overlap_out.end(),b.begin(),b.end()),"busy cache retries requested lookup and preserves hit"); NomadNetCacheFlow fields(c);k.request_data=RequestDataClass::FIELDS;fields.begin(k,101,false);fields.service();ck(fields.state()==CacheFlowState::NEED_LIVE,"request data bypass"); k.request_data=RequestDataClass::NIL;NomadNetCacheFlow reload(c);reload.begin(k,101,true);while(reload.state()==CacheFlowState::INVALIDATE)reload.service();ck(reload.state()==CacheFlowState::NEED_LIVE,"reload bypass invalidates without history-side effects"); NomadNetCacheFlow malformed(c);malformed.begin(k,101,false);while(malformed.state()==CacheFlowState::LOOKUP)malformed.service();CacheEligibility bad{true,false,false,true,false,false,RequestDataClass::NIL};ck(!malformed.acceptLive(b,bad,101)&&malformed.state()==CacheFlowState::FAILED,"malformed not committed");