Copilot commented on code in PR #12852:
URL: https://github.com/apache/trafficserver/pull/12852#discussion_r2761474507


##########
src/proxy/http/HttpTransact.cc:
##########
@@ -3270,21 +3316,53 @@ HttpTransact::HandleCacheOpenReadMiss(State *s)
     s->cache_info.action = CacheAction_t::NO_ACTION;
   } else if (s->api_server_response_no_store) { // plugin may have decided not 
to cache the response
     s->cache_info.action = CacheAction_t::NO_ACTION;
-  } else if (s->cache_info.write_lock_state == CacheWriteLock_t::READ_RETRY) {
+  } else if (s->cache_info.write_lock_state == CacheWriteLock_t::READ_RETRY && 
!s->serving_stale_due_to_write_lock) {
     // We've looped back around due to failing to read during READ_RETRY mode.
     // Don't attempt another cache write - just proxy to origin without 
caching.
-    TxnDbg(dbg_ctl_http_trans, "READ_RETRY cache read failed, bypassing 
cache");
+    // Fire the deferred CACHE_LOOKUP_COMPLETE hook with MISS result so plugins
+    // see the final cache lookup status before we go to origin.
+    // NOTE: Only fire if serving_stale_due_to_write_lock is false. If true, 
we already
+    // found a stale object and the hook was fired from 
HandleCacheOpenReadHitFreshness.
+    // We're here because authentication (MUST_PROXY) requires going to origin 
anyway.
+    TxnDbg(dbg_ctl_http_trans, "READ_RETRY cache read failed, firing deferred 
CACHE_LOOKUP_COMPLETE with MISS");
+    s->cache_info.action   = CacheAction_t::NO_ACTION;
+    s->cache_lookup_result = CacheLookupResult_t::MISS;
+    TRANSACT_RETURN(StateMachineAction_t::API_CACHE_LOOKUP_COMPLETE, 
HandleCacheOpenReadMissGoToOrigin);
+  } else if (s->cache_info.write_lock_state == CacheWriteLock_t::READ_RETRY) {
+    // READ_RETRY with serving_stale_due_to_write_lock = true means we found 
stale content
+    // but can't serve it (e.g., MUST_PROXY auth). Hook already fired, just go 
to origin.
+    TxnDbg(dbg_ctl_http_trans, "READ_RETRY stale found but requires origin, 
bypassing cache");
     s->cache_info.action = CacheAction_t::NO_ACTION;
   } else {
     HttpTransact::set_cache_prepare_write_action_for_new_request(s);
   }
 
-  ///////////////////////////////////////////////////////////////
-  // a normal miss would try to fetch the document from the    //
-  // origin server, unless the origin server isn't resolvable, //
-  // but if "CacheControl: only-if-cached" is set, then we are //
-  // supposed to send a 504 (GATEWAY TIMEOUT) response.        //
-  ///////////////////////////////////////////////////////////////
+  // If action 5/6 configured, we set NO_ACTION, and we're not in READ_RETRY,
+  // fire the deferred CACHE_LOOKUP_COMPLETE hook now with MISS.
+  // We won't enter READ_RETRY since we're not caching, so fire the hook now.
+  if (s->cache_info.action == CacheAction_t::NO_ACTION && 
s->cache_info.write_lock_state != CacheWriteLock_t::READ_RETRY &&
+      (s->txn_conf->cache_open_write_fail_action == 
static_cast<MgmtByte>(CacheOpenWriteFailAction_t::READ_RETRY) ||
+       s->txn_conf->cache_open_write_fail_action ==
+         
static_cast<MgmtByte>(CacheOpenWriteFailAction_t::READ_RETRY_STALE_ON_REVALIDATE)))
 {
+    TxnDbg(dbg_ctl_http_trans, "Action 5/6 NO_ACTION path, firing deferred 
CACHE_LOOKUP_COMPLETE with MISS");

Review Comment:
   In the action 5/6 path, CACHE_LOOKUP_COMPLETE is only fired here when 
cache_info.action == NO_ACTION. For a normal cacheable miss (PREPARE_TO_WRITE / 
PREPARE_TO_UPDATE), this function proceeds to origin without ever returning 
API_CACHE_LOOKUP_COMPLETE, and state_cache_open_read no longer calls 
setup_cache_lookup_complete_api for action 5/6. This appears to drop 
CACHE_LOOKUP_COMPLETE entirely for regular misses under action 5/6. Ensure 
API_CACHE_LOOKUP_COMPLETE still fires once per transaction for cache misses 
(e.g., fire it when write_lock_state != READ_RETRY, regardless of whether 
caching is enabled for the request).
   ```suggestion
     // If action 5/6 configured and we're not in READ_RETRY, fire the deferred
     // CACHE_LOOKUP_COMPLETE hook now with MISS. For cache misses under action 
5/6,
     // we may or may not be caching this transaction (cache_info.action could 
be
     // NO_ACTION or a prepare-to-write/update action). Regardless, we want the
     // hook to fire once per transaction for misses before proceeding to 
origin.
     if (s->cache_info.write_lock_state != CacheWriteLock_t::READ_RETRY &&
         (s->txn_conf->cache_open_write_fail_action == 
static_cast<MgmtByte>(CacheOpenWriteFailAction_t::READ_RETRY) ||
          s->txn_conf->cache_open_write_fail_action ==
            
static_cast<MgmtByte>(CacheOpenWriteFailAction_t::READ_RETRY_STALE_ON_REVALIDATE)))
 {
       TxnDbg(dbg_ctl_http_trans, "Action 5/6 path, firing deferred 
CACHE_LOOKUP_COMPLETE with MISS");
   ```



##########
src/proxy/http/HttpSM.cc:
##########
@@ -2663,7 +2666,20 @@ HttpSM::state_cache_open_read(int event, void *data)
 
     ink_assert(t_state.transact_return_point == nullptr);
     t_state.transact_return_point = HttpTransact::HandleCacheOpenRead;
-    setup_cache_lookup_complete_api();
+
+    // For READ_RETRY actions (5 and 6), skip the CACHE_LOOKUP_COMPLETE hook 
now.
+    // The hook will fire later with the final result: HIT if stale content is 
found
+    // during retry, or MISS if nothing is found (from 
HandleCacheOpenReadMiss).
+    // This ensures plugins see only the final cache lookup result, avoiding 
issues
+    // like stats double-counting and duplicate hook registrations.
+    if (t_state.txn_conf->cache_open_write_fail_action == 
static_cast<MgmtByte>(CacheOpenWriteFailAction_t::READ_RETRY) ||
+        t_state.txn_conf->cache_open_write_fail_action ==
+          
static_cast<MgmtByte>(CacheOpenWriteFailAction_t::READ_RETRY_STALE_ON_REVALIDATE))
 {
+      SMDbg(dbg_ctl_http, "READ_RETRY configured, deferring 
CACHE_LOOKUP_COMPLETE hook");

Review Comment:
   Deferring CACHE_LOOKUP_COMPLETE here based only on config value (action 5/6) 
causes the hook to be skipped for *all* cache open_read failures, including the 
normal cache-miss path (write_lock_state == INIT). In that normal miss case, 
HttpTransact::HandleCacheOpenReadMiss currently does not always re-fire 
API_CACHE_LOOKUP_COMPLETE, so plugins may never see CACHE_LOOKUP_COMPLETE for 
misses when action 5/6 is configured. Consider deferring the hook only when we 
are actually in the READ_RETRY loop (e.g., when cache_info.write_lock_state == 
READ_RETRY), and keep the original immediate hook behavior for ordinary misses.
   ```suggestion
       // For READ_RETRY actions (5 and 6), skip the CACHE_LOOKUP_COMPLETE hook 
only
       // when we are actually in the READ_RETRY loop. For ordinary cache misses
       // (e.g. write_lock_state == INIT), keep the original immediate hook 
behavior
       // so plugins always see CACHE_LOOKUP_COMPLETE for misses.
       if ((t_state.txn_conf->cache_open_write_fail_action ==
              static_cast<MgmtByte>(CacheOpenWriteFailAction_t::READ_RETRY) ||
            t_state.txn_conf->cache_open_write_fail_action ==
              
static_cast<MgmtByte>(CacheOpenWriteFailAction_t::READ_RETRY_STALE_ON_REVALIDATE))
 &&
           t_state.cache_info.write_lock_state == 
HttpTransact::CacheWriteLock_t::READ_RETRY) {
         SMDbg(dbg_ctl_http, "READ_RETRY configured and in READ_RETRY state, 
deferring CACHE_LOOKUP_COMPLETE hook");
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to